Permanently change CSS Property with Javascript/D3JS/JQuery - javascript

Is there a quick and easy way to 'permanently' change properties of CSS with Javascript, D3JS, or JQuery? I've found this question which will change geometry already existing:
$('.myClass').css({ ...Your CSS properties here... });
However, I want to change a CSS property so that the geometry that is created in that session will have these updated changes as well. How can I, using Javascript, change the CSS class below from a stroke of steelblue to a stroke of light grey?
.P0{ fill:none; stroke-width:1.25px; stroke:steelblue;}

Magic CSS colour changing fiddle:
http://fiddle.jshell.net/8xkv3/3/
The key idea is to access the last stylesheet in the CSS Object Model, and add at the end of that stylesheet a CSS rule specifying the property you want for the selector you want. You want the last rule of the last stylesheet, so that it over-rides anything else in the cascade (except inline styles, of course).
The stylesheet objects in effect for the document are available as a list at document.styleSheets. Each one has a property cssRules which is a list of rules, which each represent a selector plus a list of property-value pairs.
The stylesheet.insertRule() method creates a new rule from a string, and adds it to the sheet at the specified index. Unfortunately, it just returns the index, not the rule object, so we have to re-select it to save for future modification.
You could just repeatedly add on new rules, each over-riding the previous, but that's not very efficient. The rule object has a "style" map with keys and values acting pretty much as you'd predict.
Edit
I realized there is a problem with the above approach. What happens if the last stylesheet in the list isn't being used by the current web-page? What if it's a print stylesheet? Or a stylesheet for tiny screenss, or speech synthesizers, or any other media-query limited situation? You could add a rule to that stylesheet object, but it wouldn't have any effect.
Clearly, what you need to do is create a new stylesheet object with no restrictions and/or with only the restrictions you chose. Then you can add this stylesheet to the end of the list and add your dynamic style rules to it.
You can't create a stylesheet object directly, but you can create a <style> element and add it to the html head object in the DOM. When the <style> object is added to the document a stylesheet object will be created for it, and can be accessed as the .sheet property of the element.
The amended fiddle is here: http://fiddle.jshell.net/8xkv3/6/
Key code:
if (!rule) {
//create a new page-wide style element
var styleElement = document.createElement("style");
styleElement.type = "text/css";
//probably not necessary (CSS is default),
//but it doesn't hurt to be explicit
document.head.insertBefore(styleElement, null);
//once inserted in the document, a valid
//CSSStyleSheet object is created and attached
//to the styleElement object
var styleSheet = styleElement.sheet;
var ruleNum = styleSheet.cssRules.length;
//console.log(styleSheet);
styleSheet.insertRule(
".changeable{color:#"+hex[1]+";}",
ruleNum);
rule = styleSheet.cssRules[ruleNum];
//console.log(rule);
}
else {
rule.style["color"] = "#"+hex[1];
};
By the way, I don't know why this didn't show up when I searched MDN previously, but here's a good article on the various ways of dynamically manipulating the CSS OM:
https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_dynamic_styling_information

Related

Adding an html element around text that does not affect the page (for tooltip)

I have built a tooltip plugin here:
http://shawntabrizi.com/cryptip/
Source here: https://github.com/shawntabrizi/cryptip/blob/master/webextension/content.js
The basics here is that I use Tippy.js to add a tooltip around certain matching text to display price information.
To do this, I look through the HTML body, find any text nodes, and then search that text node for the matching text. If I find matching text, I modify the text to include a <span> with a certain class in order to trigger Tippy.js.
Here is the relevant code:
if (node.nodeType === 3) {
var text = node.nodeValue;
if (reCoins.test(text)) {
text = text.replace(reCoins, function (a, b) {
console.info('Adding cryptip to:' + b, element.tagName)
let priceString = createPriceString(coindict, b, currency, time);
return `<span class="cryptip" title="${priceString}">${b}</span>`;
});
var replacementNode = document.createElement('span');
replacementNode.innerHTML = text;
node.parentNode.insertBefore(replacementNode, node);
node.parentNode.removeChild(node)
}
}
However, I have received reports that on some pages, the span element is picking up styling which affects the rendering of the page. One example of a page is https://yout.com/ which has a default styling on span elements nested in certain areas creating a problem like this:
I tried a solution where I set the CSS on the element to be:
.cryptip {
all: unset;
}
However, the page seems to be loading other styles on top of it:
So I guess my questions are:
Is there some CSS trick I can do to avoid my element being styled? Maybe create a CSS styling with every possible style element for a span, and set it to default with the !important attribute.
Is there another 'psudo' element in HTML that I can use which does not affect the page rendering? Something like <foo class="cryptip"></foo> should work for getting tippy on the page, but does there exist such an element?
If you use an HTML Tag declaration that isn't recognized the node is created from an HTMLUnknownElement prototype, which doesn't have its own properties and methods, but acts as a pass-through to inherit everything from HTMLElement. HTMLElement is the prototype that offers your most base element methods and properties such as offsetHeight and style
You can imagine then that there is no designated pseudo element because any unassigned tag can be used, though if you can style the specific tag you're looking to replace instead that would obviously be preferred for posterity.
If you have to, in your current use case, use an unassigned tag, because of it's prototype it is setup like other elements and you will be able to search for it in the DOM. A section tag is directly inherited from the HTMLElement prototype, and you can think of the unknown tag similarly since all it has between it and the HTMLElement prototype is an empty object. It's also worth noting that there is a customElements spec being looked at by the w3c but its support is sparse.
To summarize there aren't any real drawbacks currently that I'm aware of except maintainability of the codebase(you're going to want to be sure to document well that you are adding a tag) and you may have to be prepared to change it if, for instance, in the future Custom Elements require a declaration - and always keep in mind that there's no guarantee it will always work as well as it does now since there is no spec on the issue and Browsers are fickle.

How can I copy a block on one page to another page retaining css stylings?

Say I've got two pages whose javascript can talk to each other, via the return value of window.open(), or window.opener. The pages can (and typically will) have completely different css rules.
I pick an arbitrary node in the DOM heirachy of one page (say, a DIV element). I now insert a clone of it into the other document, at some arbitrary (but legal) location in the hierarchy.
Now I also want to create css rules that keep it looking similar on the new page. I prefer minimal number of properties on the css rules.
Can I do this by doing some kind of comparison of styles and computed styles on the DOM elements of both documents? Would it help if I were to remove the classes from elements temporarily, or otherwise modify them, so that I can get the computed styles on the elements with "default" styles, and compare to that?
http://jsfiddle.net/1ruvsqw1/1/
var e = document.getElementsByClassName('test')[0],
div = e.cloneNode(true),
newStyles = getComputedStyle(e);
document.body.appendChild(div);
var existingStyles = getComputedStyle(div);
for (var i in existingStyles) {
console.log(i, existingStyles[i]);
if (newStyles[i] != existingStyles[i]) div.style[i] = newStyles[i];
}
Just copy the computed styles over in a for-in loop.

Change CSS class content from javascript [Firefox/XUL]

I'm working on a firefox addon, and relies heavily on some dynamic changes with javascript. There are some UI elements (hbox/descriptions), which are styled using CSS classes. Now I wish to change the a CSS class defintion from javascript, without having to work element id's. Is it possible ?
Similar questions had been asked before, but most of them are using php to generate a CSS or jquery based changes.
Here's an example for my scenario:
My XUL :
<box id="firefox-addon-box">
<description id="description-1" class="description-text"> Some description </description>
<description id="description-2" class="description-text"> Some description </description>
</box>
My CSS :
.description-text {
font-size: 15px;
color: #fff;
}
So I wish to change the font-size in description-text class to say, 20px dynamically.
Now I know that we can change the style using individual id's, with a getElementById() and changing the style. But here I wish to change a class (which matters to a lot of elements), rather than to work on individual ids.
I also know that we can point to another class definition by setAttribute() and change 'class' - this would again require working on individual id's. In reality, I have plenty of UI elements (all pointing to one CSS class), and many values changed in a CSS class. So my question is, is there a way to directly change a CSS class definition from javascript, without having to work on element ids ?
Thanks for any help.
myVar = document.getElementsByClassName("description-text");
document.getElementsByClassName
I asked a very similar question last night and figured it out this afternoon, which I have just tested as working on Firefox 29.0b1-49.0a1, may work on earlier versions, not sure about newer versions once XUL is removed (SDK or WebExtensions), but as it is pure JS/DOM/CSS, I think it might work ok.
What I learned was that it is easier than I thought. Essentially, you find the specific style sheet, the specific rule, and edit the "style" of that rule using DOM, just like in HTML.
document.styleSheets[ i ].href
document.styleSheets[ i ].cssRules[ j ].selectorText
document.styleSheets[ i ].cssRules[ j ].style.fontSize
It all starts with the document.styleSheets array-like object, where i is the outer document.styleSheet loop index and j is the cssRules inner loop index.
The href is optional to consider, and is the URI of the style sheet. If known, and if the sheet is not dynamically generated, and if you are certain that the selector you want exists only in that one file, then you can use it to limit searching through all selectors in all the ~10 style sheets that Firefox loads by default, before your add-on's first sheet is ever loaded.
Otherwise, you loop through all document.styleSheets, (optionally skip if href doesn't match), then loop through all the cssRules on each style sheet, and see if the .selectorText matches your desired selector, in the case of the OP: .description-text (note that you need the leading . or # etc, exactly as it appears in the CSS file, for classes or IDs, etc).
When you find the selector you want, then you can modify the .style object (well documented at W3Schools DOM Style Object). In the OP example, we want to change the font-size style to 20px, which would be .style.fontSize = '20px'.
Using these fundamentals, a more generic function can be crafted, to more easily reuse. Perhaps a getCSSrule function which takes a required selector and an optional href argument, which will help you by getting the sheet and rule you want. Perhaps a getCSSsheet function if you want to use just the href to get a sheet. Perhaps a setStyle function to set the style and value. Perhaps a set of delCSSsheet and delCSSrule functions if you want to discard these rather than modify. And also an insCSSsheet and insertCSSrule function, maybe a createCSSsheet and createCSSrule as well.
This url (Totally Pwn CSS with Javascript), despite the name, and defunct Web Archive only status, and being 9 years old or more, is actually still relevant.
I will refrain from advising in favour of this method, but it is possible to also directly add css rules (or more complex remove them) doing the following
var css = '.description-text { font-size: 100px; }',
head = document.getElementsByTagName('head')[0],
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
There are rare occasions where this is a possible way to go and many situations where this is not the proper thing to do. You should never do this if you plan on overwriting the same thing multiple times (except if you remove the old rule first) and should only do this if you will use some other feature of CSS which builds upon this (e.g. new elements getting properly styles, 3rd party content getting properly styled, css animations, etc.).
I had to do the same few months ago. I solved it with jQuery with .addClass() and .removeClass() and more http://api.jquery.com/category/css/
Or if you want only Javascript use the HTML DOM from pure Javascript. Official documentation about that with examples: http://www.w3schools.com/js/js_htmldom_css.asp
Using JQuery you could use the css property :
$(".description-text").css({backgroundColor: "#ffe", borderLeft: "5px solid #ccc" });
All your elements that use the description-text class will be affected
Documentation of jquery css property
EDIT
Or with pure javascript
var elements = document.getElementsByClassName('description-text');
for(var i=0; i<elements.length; i++){
elements[i].style.backgroundColor = "#ffe";
elements[i].style.borderLeft = "5px solid #ccc";
//any style you want to apply
}
Documentation of javascript style

Javascript document.defaultView or document.styleSheets?

When we want a more reliable way to get the style of an element, we use
document.defaultView.getComputedStyle..
instead of
document.getElmById(x).style.color..
BUT, there is another, and it is
document.styleSheets...
I'm new to JS, I just read about document.styleSheets today. And my question is:
When we want to get just one style property (example: color), which should I use?
What is document.styleSheets for? When should it be used?
When we want to add a method that looks like this:
// it applies multiple properties
elm.setStyle({
color: '#f00',
marginLeft: x,
opacity: 0.5,
background: '#000 url(x.jpg) left top no-repeat'
});
Which should I use to be the base of the function?
Finally, Thanks for all your help!
document.styleSheets is the list of the actual stylesheet or sheets loaded into the page. Fun fact: you can dynamically create new "stylesheets" and add them to this list, without actually loading separate files.
If you are looking up the current style of an element, the question you need to ask is, "do I care more what the stylesheet SAYS the style should be, or do I care more what the actual current (computed) style is?" The circumstances will determine which is more appropriate.
If you care about the original declared styles, you'll want to consult the stylesheets themselves. However, this is quite a bit more complex than it may seem, because you're going to have to parse the files and find all the cascading styles that would apply to the element in question.
If you care about what the current computed styles are, getComputedStyle() is more reliable that .style.
Now, for setting, if you want to apply a style rule directly to a single element, you'd want to use .style, but if you want to create a new rule that applies to many (and future!) elements, you'd want to create a dynamic stylesheet/rule and append it to the .styleSheets collection.

Is there a (polyfill) code that resets all the inherited CSS properties on a given element?

The subject says it all. Looking for a (polyfill) code that will reset all the inherited CSS properties on a given element (such as <img>, <a> or <p>).
If you want to completely reset everything to the browser's default styling, then the modern CSS approach is to use the revert keyword with the all property:
all: revert;
From MDN,
The revert CSS keyword rolls back the cascade so that the property takes on the value it would have had if there were no styles in the current style origin (author, user, or user-agent). In author stylesheets (the normal case), for the purposes of the given declaration, it's as if there were no author-level styles, thus resetting the property to the default value established by the user-agent stylesheet (or by user styles, if any exist).
Caveat: It is defined in the CSS Cascading and Inheritance Level 4 working draft, so browser support is currently limited to Safari only.
What you could do is create one of those elements but not attach it to the DOM. It wouldn't then receive any of the styles from your stylesheets. Then, using window.getComputedStyle, you will get a list of the default styles.
var a = document.createElement('a');
var s = window.getComputedStyle(a);
myTargetEl.style.color = s.color; // or, use a loop to do all of them
May be you can use HTML5 boilerplate or css Reset to reset all the inherited CSS properties.
check these articles http://html5boilerplate.com/ ,
http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/
This sounds like the all property, which sadly is not yet implemented by any browser other than Firefox.
Example:
h2 {
all: initial; // Will reset any style set for h2 elements
}
See https://developer.mozilla.org/en-US/docs/Web/CSS/all

Categories

Resources