How to change .css priority with javascript - javascript

I need to change priority of loaded .css files using javascript. I found that i can do this just by replacing position of < link rel="stylesheet".... >tag in the head element. This solution works fine in all browsers except IE. I am using the following code for this:
var firstCss = styleSheets[0].ownerNode;
var defaultCss = styleSheets[1].ownerNode;
firstCss.parentNode.insertBefore(defaultCss, firstCss);
So is there a better solution for such issue, or maybe somebody know how to make this code work under IE.

I solve the problem maybe not in the best way but it works. I wrote the following code:
if (document.createStyleSheet) {
document.createStyleSheet(defaultCss.href,0);
defaultCss.cssText = "";
} else {
firstCss.ownerNode.parentNode.insertBefore(defaultCss.ownerNode, firstCss.ownerNode);
}
I use "defaultCss.cssText = "";" to cleanup old CSS file, cause you can't get ownerNode of styleSheet under IE7-8(but you can do it in IE9) and delete old style sheet. So if you even load your CSS file to first position you will still have the same on the last position and it will be prioritized. I check it works under IE 7 - 9 and other borwsers, also stylesheet doesn't loaded from server again IE take it from cache.
hope it will be useful for someone.

The order in which you load your CSS files has very little influence in how styles are applied. What styles are applied to a certain element is determined by the specificity of the selectors used in the CSS rule. A higher specificity overrules a lower specificity, even if the style with the lower specificity is declared later.
The specificity can be seen as a combination of four digits in the form (a,b,c,d) where a takes precedences over b and b over c and c over d. So (0,0,0,2) has a higher specificity than (0,0,0,1) and (0,0,1,0) has a higher specificity than (0,0,0,2).
The order of style declaration (i.e. the order in which style sheets are loaded) is only important if selectors are used with exactly the same specificity.
For Example:
A: h1
B: #content h1
C: <div id="content">
<h1 style="color: #fff">Headline</h1>
</div>
The specificity of A is 0,0,0,1 (one element), the specificity of B is 0,1,0,1 (one ID reference point and one element), the specificity value of C is 1,0,0,0, since it is an inline styling.
Since
0001 = 1 < 0101 = 101 < 1000,
the third rule has a greater level of specificity, and therefore will be applied. If the third rule didn’t exist, the second rule would have been applied.

Related

How to get the inherited values of element from JavaScript

Okay, so I've a script that gets the CSS property value of a clicked element. For this, I avoided window.getComputedStyle() because it basically converts rem values to px and so on...
Instead, I've used CSSStyleSheet.cssRules just to keep the originality of the actual given units and not converting them.
And this does works fine! but it fails to capture CSSRules that are inherited from the parent element since the styles are not directly applied to the element.
For example:
<style>
#new {
font-size: 2rem;
}
</style>
<div id="new">
<h1 class="h1">This is a heading</h1>
<!––Here h1 is inheriting font-size from div that can't be catched by CSSRules––>
</div>
For this case, getComputedStyle() works the best as CSSRules failed to catch the inherited properties but again, the problem of units arises so I cannot use that.
Or maybe something to get the metric unit of an element? 🤷‍♀️ That would do the job too!
Although Chrome seems to have figured this out perfectly:
It's 2022 and I've checked other answers too but seems like nobody has figured this out yet. What's the current solution to this? Or the best hack?
Edit1:
I want the same string as defined in the CSS by the user. Like: calc(2rem + 1vh) And with CSSRules it is working but it doesn't works with inheritance because it's not even catching the property! ComputedStyle does that but in px I'm kinda stuck here.
Edit2:
I've chosen Lajos Arpads answer as the accepted one because of the help I recieved in the comments (not the actual answer itself). The solution is going to be labor intensive so it's something I've to do.
You can simply implement a pixel-to-rem converter and use that:
function convertPixelsToRem(pixels) {
return ((pixels.replace("px", "") / getComputedStyle(document.documentElement).fontSize.replace("px", "")) + "rem");
}
console.log(convertPixelsToRem(window.getDefaultComputedStyle(document.getElementById("new").querySelector(".h1"))["font-size"]));
<style>
#new {
font-size: 2rem;
}
</style>
<div id="new">
<h1 class="h1">This is a heading</h1>
<!–– Here h1 is inheriting font-size from div ––>
</div>
EDIT
You could do something like this:
getOriginalRule(ruleName, ruleValue, item) {
while (hasSameRule(item.parentNode, ruleName, ruleValue)) item = item.parentNode;
//return the rule value based on the item via CSSStyleSheet.cssRules
}
EDIT2
As per the ideas discussed in the comment section, with the goal being to be able to gather the raw rules applied either directly or by inheritance to nodes, there are two main solutions:
one can loop through the rules, find the elements they apply to and then loop the DOM tree to descend the raw rules where they were not overriden
one can loop the DOM tree from top to bottom and find all nodes, compare each node's rules with its parent's rules and if they differ, descend the parent's rules
The main difference between the two is that the first is starting with all the CSS rules, while the latter only uses the values.

Determine if any CSS rule directly modified an element's style

Suppose I have
HTML
<foo>
<bar>
<baz>Hello!</baz>
</bar>
</foo>
CSS
foo {
color: red;
}
bar {
color: red;
}
How can I take an element and determine whether its color style attribute was the result of matching a direct CSS rule or by inheritance?
// foo -> true - the first CSS rule directly applied a color to this element.
// bar -> true - the second CSS rule directly applied a color to this element. It didn't change the color that would have been inherited, but that's ok.
// baz -> false - The color in this element is purely inherited.
function isColorSetDirectly(DOMElement) {
...?
}
Using JS, I:
Can determine the effective color of text (Hello!) in a tag (baz) using getComputedStyle.
Can tell if a style was applied directly with HTML using the style attribute by checking element.style.color.
Can't tell if the rule that determined the style was directly applied to the element or if the element inherited the rule.
If CSS rules could be exhaustively enumerated, I could use element.matches/matchesSelector for every CSS rule that defines color. But since CSS rules can be set anywhere (external stylesheet, inline style tag, element style attribute, etc.) it seems difficult to enumerate all CSS rules that could affect an element.
The code initially loaded with the page (HTML/CSS) can't be changed but may be freely manipulated with JS.
Bonus
Is there a way to find out which element baz is inheriting its color from?
You can use window.document.styleSheets[i].rules to get CSS rules. You can get the selectorText, style, or the full cssText. For info on how to use this: https://stackoverflow.com/a/27527462/804495
All stylesheets, regardless of if it was included via <link> or <style> will be in window.document.styleSheets. However, this will not get element style.
To resolve this, you can use getComputedStyle on an element as you mentioned. If an element has a style declaration that is not in any of the styleSheets, then you know it is an inline style= CSS rule, either applied directly or through its ancestor chain.
Is there a way to find out which element baz is inheriting its color from?
It's possible. To find out which element it is inherited from, you will have to iterate through the parent elements; however based on the way CSS declarations work this should be exhaustive.
Use browser developer tools. Most modern browser has developer tools to help you debug CSS, javascript, network problems. Press F12 to start in Chrome, firefox (firebug plugin) and IE.
http://developer.chrome.com/devtools
http://msdn.microsoft.com/en-us/library/dd565628(v=vs.85).aspx

After a background color change with Javascript the :hover don't change the color

I have a long form with many fields. Some of the fields get their data from separate DIV, where there are other more specific fields.
Every field, along with its label, is included into a separate block. To highlight the fields there is a CSS :hover for their class.
The CSS :hoveron the fields blocks works smoothly, and also the onmouseover and onmouseout over the many DIV passing data to them, using the following Javascript:
function LineOn(whichOne) {
document.getElementById(whichOne).style.backgroundColor = '#cf0';
}
function LineOff(whichOne) {
document.getElementById(whichOne).style.backgroundColor = '#fff';
}
But, after the execution of the Javascript, the hover stops to work (i.e. the block remains white), without reporting any console error or message.
This happens both with Firefox 36.0.3 and with Chrome 39.0.2171.71, running on a Slackware current release.
Is there a sort of hierarchy giving to the background color set with Javascript the priority over the one defined in the <style> section?
Yes, styles defined directly in the element's style property overrides any value set in CSS, unless that style has !important on it.
CSS specificity http://www.w3.org/wiki/CSS/Training/Priority_level_of_selector
The priority level of the selector is decided in Point of combination of selectors.
style attribute = a
number of ID attributes in the selector = b
number of other attributes and pseudo-classes in the selector = c
number of element names and pseudo-elements in the selector = d
That's one good reason not to set styles attributes; set a CSS class instead yet.

CSS: specificity not behaving for js injected stylesheets?

As part of a mobile-first build, i am loading the 'desktop' css dynamically in a blocking fashion
<script type="text/javascript">
var mq = window.matchMedia("(min-width: 640px)");
if(mq.matches){
var stylesheet = document.createElement('link');
stylesheet.href = '<?php echo $src ?>';
stylesheet.rel = 'stylesheet';
stylesheet.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(stylesheet);
}
</script>
However, webkit and ff give more power to the css loaded pre-injection.
Even if SetTimeout 3 seconds before loading mboxes.css, the browsers still favour the css rules that were not injected.
How can i get the css specificity rules to behave?
The problem is the ordering of the CSS that is being loaded, it is loading the values of event_core as the master so to override this you have 2 easy options without rewriting the js.
You can execute the Javascript before the event_core.css or after depending what you have at the moment.
Or the easiest way but depends realistically how much CSS you have in mboxes.css would to use !important within the CSS which will tell the browsers these are most important and become the new master.
For example
.mob p {
color:white!important;
}
Or make the edit the rules so that both are the same, for example .content > .mbox p
Ok, worked this out.
For the CSS to behave "normally" it needs to be injected into the <body> not the <head>.
document.getElementsByTagName('body')[0].appendChild(stylesheet);
The problem has nothing to do with the way the css files is loaded and more to do with the rules of css precedence. Basically, the more specific the selector, the higher priority the rule has. In your case both selectors are the same priority (class and element selector), so some browsers will choose one, other the other the last loaded should override the first, but it's not something I would count on.
The fix is to make the rules in mboxes.css more specific like .mbox.main_content p.
A second option is to add !important after each style like (like color: white !important), but I would recommend against that.

Quickly repaint array of unicode symbols in JavaScript

I want to change background/foreground color of many symbols with the same CSS class. Right now I'm doing it with jQuery — like $('back_COLORED').css('background-color', '#00FF00'), but this approach is slow when there are many elements with such class (>900).
Seems it's because jQuery don't change CSS rules itself, but finds all elements one-by-one and applies inline styles to them. At least, this is what I see in inspector. So, the question is:
How can I change the CSS rules itself?
Will it be much faster?
Can I make it cross-browser (IE6 doesn't count)?
UPD: I'm trying to make some kind of color scheme editor. The source is at http://github.com/kurokikaze/cinnabar/. Don't mind PHP things, editor is fully client-side (with just some libraries fetched from the net).
UPD2: Tried canvas approach, still slow. Canvas branch is at http://github.com/kurokikaze/cinnabar/tree/canvas.
The most cross-browser friendly way to override a class definition is to write a new rule and add it to the end of the last stylesheet in the document. You can edit an existing style rule, but even some recent browsers can make it difficult.
function newRule(selector, csstext){
var SS= document.styleSheets, S= SS[SS.length-1];
// this example assumes at least one style or link element
if(S.rules){
S.addRule(selector,csstext,S.rules.length);
}
else if(S.cssRules){
S.insertRule(selector+'{'+csstext+'}'),S.cssRules.length)
}
}
newRule('.someclass','background-color:#0f0');
You can add as many 'property:value;' bits in the csstext as you need.
Remember to prefix a '.' to a class name or a '#' to an id,
and the css must be written as a style rule (with-hyphens, not camelCase).
Of course, it will not override inline styles, and it is overkill for small, local changes.
It also may make the redrawing of the page more obvious than changing one element at a time,
but it may be just what you need here.
There are different ways depending on which browser you are dealing with. This is documented on Quirks Mode.
Some libraries provide an abstraction layer, such as YUI's StyleSheet utility.
There should be a significant performance boost since you aren't using JS/DOM to cycle through all the elements.
Another approach would be to predefine your styles:
body.foo .myElements { … }
And then edit document.body.className
If you can select the parent div by id, maybe you could select by tag inside it? Or are there elements of the same kind that should change color and that should not, inside the parent?
It would be nice to have an idea of what you're building here. 900+ objects seems to be a lot... maybe a completely different approach could be used? Canvas, SVG?
Try hiding the items you want to change before changing them, make the change and then display them again. This is common practice to speed up things as you minimize the repaint events in the viewport. In this case when you only setting one css property it might not be that of a benefit but it´s worth a try I say.
Try:
$('back_COLORED').hide();
$('back_COLORED').css('background-color', '#00FF00');
$('back_COLORED').show();
or
$('back_COLORED').hide().css('background-color', '#00FF00').show();
I would stick in trying changing a CSS property, instead of parsing the DOM.It is about the CSS engine vs. DOM+JS here, and the winner is clear.
It happens I just uploaded a tiny library that replaces CSS by Javascript: jstyle
This is may be an overkill, but you will find in the source code of jstyle.js all the code you need to update cross browser the CSS properties of your page.
I think a better solution would be to write a more specific CSS rule (that would override the normal colour) that can be activated by simply changing one element's css class.
So for example if you had the following structural markup:
<div id="container">
<span class="colored">Test 1</span>
<span class="colored">Test 2</span>
</div>
And CSS:-
.colored { background-color: red; }
.newcolor .colored { background-color: blue; }
Then in your jquery you add the .newcolor class to the container div:-
$('#container').addClass('.newcolor');
When you do that the second CSS rule will override the first because it is more specific.
Inject the css code into a style tag:
var style = $('style').attr({
type:"text/css",
media:"screen",
id:'changeStyle'
}).html('.tempClass { color:red } .tempClass p { background:blue }').prependTo('body');
and on every changes on your color with color picker you only rewrite the html inside of #changeStyle tag.
Have no idea if it works (didn't tested) but you should give a try.
This is jQuery pluggin for work with css rules: http://flesler.blogspot.com/2007/11/jqueryrule.html
not sure about its performance, but worth a try.

Categories

Resources