Can !important rules be used in IE's CSS expressions? - javascript

Firstly, I know that CSS expressions are defunct and wrong in so many ways, and also to avoid using !important where possible. This is for a special case stylesheet.
In Short
My question is... Is there any way for a CSS expression to set the !important flag?
E.g. this doesn't work:
a { color:expression('red !important'); }
[Edit: thanks to MarmaladeToday's comment below]. This also doesn't work:
a { color:expression('red') !important; }
Can this be done some other way?
In Detail
What I'm actually trying to do is mimic the inherit value in IE6 & 7. This works:
color:expression(
this.parentNode.currentStyle ?
this.parentNode.currentStyle.color: 'red'
);
But I also want to set the !important flag, and this doesn't work:
color:expression(
(
this.parentNode.currentStyle ?
this.parentNode.currentStyle.color: 'red'
) + ' !important');
I'm aware that, in JavaScript, it isn't possible to set !important via an element's style object. E.g. this won't work:
element.style.color = 'red !important';
However, it is possible to set !important via the element's style attribute:
element.setAttribute('style', 'color:red !important;');
So... are CSS expressions limited to interacting with the style object, and therefore, what I want to achieve is impossible - or is there any way for an expression to affect an element's attributes, or pass !important in some other way?
Starting a Bounty
No solid answers so far, so I'm starting a bounty.
Ideally, I'm looking for a CSS-based solution for mimicking inherit !important in IE6 and IE7, either with or without CSS expressions. (Please do verify that your suggestions work before posting).
At least, a link to some authoritative reference telling me that this is impossible would mean I could lay this train of thought to rest - I've not seen anything mentioning the use of CSS expressions with the !important rule.

The reason those CSS expressions don't work is because IE only evaluates the expression for the last property in the cascade.
E.g. if you have an HTML document with a link inside it and the following "CSS",
a {
color: expression(function(e){
alert('success');
e.runtimeStyle.color = 'blue';
}(this));
}
a { color: red; }
you will never see that alert (nevermind the style change), because the CSS expression is never evaluated. So no, you can't use an expression to set the !important flag.
That is to say, not when you try to set it on the same property. You can cheat. But that does make the expression a bit more complicated:
a {
filter: expression(function(e){
e.runtimeStyle.color = 'blue';
alert('success');
e.style.filter = '';
}(this));
}
a { color: red; }
There are a few things to note here.
If you simply use another CSS property, you can be sure that the expression will be evaluated. Or at least, a little more sure, because if there's another rule further down the cascade that uses the same property already, you're still out of luck.
Secondly, you have to use runtimeStyle instead of currentStyle. If you used currentStyle here, the second rule would still end up overwriting it. runtimeStyle overrides all other CSS (except !important declarations). So it's the JScript equivalent of !important.
Also note that I'm resetting the filter property itself as well. That prevents the expression from being continuously re-evaluated. But as much as that may reduce performance, I don't think it's super critical. The main reason I put it in here is because I added alert()s in those expressions, and you definitely don't want to have those pop up forever.
It is in fact also possible to use any other property you make up. This works too:
a {
bogus: expression(function(e){
e.runtimeStyle.color = 'blue';
}(this));
}
However, since the bogus property doesn't actually exist, you can't reset it using Javascript, so this will be re-evaluated continuously.

color:expression('red') !important;

You could try the behavior property, it's a lot more versatile than expressions.
Try this,
inherit.htc :
<SCRIPT language="JScript">
//add your own inheritance logic here, you can use element.parentNode etc.
var prop = element.currentStyle.behaviorProp;//specified in stylesheet
var val = element.currentStyle.behaviorValue;//specified in stylesheet
element.style[prop] = val;//set as inline style, you can also use setAttribute here.
</SCRIPT>
css:
body #div1 {
color:blue;
}
#div1 {
color:red;/*stays blue, because 'body #div1' is more specific*/
behaviorProp:color;/*specify styleproperty for the .htc*/
behaviorValue:green;/*WILL become green, because the .htc sets it as an inline style, which has priority.*/
behavior:url(inherit.htc);
}

This sounds sick and evil, but:
color: expression((function (_this) {
window.setTimeout(function () {
_this.setAttribute("style", "color:" +
(_this.parentNode.currentStyle ?
_this.parentNode.currentStyle.color : 'red') + " !important";
}, 0);
return _this.parentNode.currentStyle ?
_this.parentNode.currentStyle.color : 'red';
})(this));
In other words, this:
Returns "red" (or the parent color) immediately.
Sets a timeout that will set "red !important" (or whatever) immediately after.
Keep in mind that this could end up hosing your browser though. I didn't test it, and stuff involving CSS expressions tends to go terribly wrong.

The venerable ppk of quirksmode has done some work on CSS, JavaScript and the !important keyword. (Note that for test in Firefox or any other non-IE browsers, use cssRules instead of rules below.
Here's the link: W3C DOM Compatibility
You can apparently read whether a style rule in a stylesheet is important by doing this (this would get the importance level of the color property in the 2nd css rule in the 2nd stylesheet, IN ALL BROWSERS EXCEPT MICROSOFT INTERNET EXPLORER. How's that for a bummer.
document.styleSheets[1].rules[1].style.getPropertyPriority('color')
//Returns important when the style is marked !important.
//Returns an empty string otherwise.
Now, his research reveals yet another way to set !important, unfortunately this also apparently only works in non-Internet Explorer browsers
// where x is a DOM element
x.style.setProperty('color','#00cc00','!important');
// Set the color of x or the second rule in the second style sheet to green.
document.styleSheets[1].rules[1].style.setProperty('color','#00cc00','!important');
Apparently this strange syntax, if you are not setting things as !important, requires setting the third parameter to null:
// where x is a DOM element
x.style.setProperty('color','#00cc00',null);
// Set the color of x or the second rule in the second style sheet to green.
document.styleSheets[1].rules[1].style.setProperty('color','#00cc00',null);
Now, MSDN has a property called "cssText" that dangles off the style object of a DOM element. It even indicates that CSS expressions are okay. The usage is:
x.style.cssText = 'color: #00cc00 !important';
Now, this may be important (heh), the MSDN page says (emphasis mine):
DHTML expressions can be used in place of the preceding value(s). As
of Internet Explorer 8, expressions
are not supported in IE8 mode. For
more information, see About Dynamic
Properties.
It may be worthwhile to check out ppk's tests of cssText as well.
I unfortunately don't have the relevant versions of Windows Microsoft Internet Explorer available on this laptop, but perhaps this is of some use. I'm curious to how this shakes out, it's something I'd run into (setting !important in JavaScript) but found other ways to get around it, typically just shifting around classes or applying specificity by using an ID in the relevant selectors.
Best of luck on an interesting question!

It's been my understanding that !important is largely these days as a hack... specifically because IE does NOT recognize it.

Related

is there a way to write hover code inside style="" attribute in HTML? [duplicate]

Is it possible to have pseudo-classes using inline styles?
Example:
Google
I know the above HTML won't work but is there something similar that will?
P.S. I know I should use an external style sheet, and I do. I was just curious if this could be done using inline styles.
No, this is not possible. In documents that make use of CSS, an inline style attribute can only contain property declarations; the same set of statements that appears in each ruleset in a stylesheet. From the Style Attributes spec:
The value of the style attribute must match the syntax of the contents of a CSS declaration block (excluding the delimiting braces), whose formal grammar is given below in the terms and conventions of the CSS core grammar:
declaration-list
: S* declaration? [ ';' S* declaration? ]*
;
Neither selectors (including pseudo-elements), nor at-rules, nor any other CSS construct are allowed.
Think of inline styles as the styles applied to some anonymous super-specific ID selector: those styles only apply to that one very element with the style attribute. (They take precedence over an ID selector in a stylesheet too, if that element has that ID.) Technically it doesn't work like that; this is just to help you understand why the attribute doesn't support pseudo-class or pseudo-element styles (it has more to do with how pseudo-classes and pseudo-elements provide abstractions of the document tree that can't be expressed in the document language).
Note that inline styles participate in the same cascade as selectors in rule sets, and take highest precedence in the cascade (!important notwithstanding). So they take precedence even over pseudo-class states. Allowing pseudo-classes or any other selectors in inline styles would possibly introduce a new cascade level, and with it a new set of complications.
Note also that very old revisions of the Style Attributes spec did originally propose allowing this, however it was scrapped, presumably for the reason given above, or because implementing it was not a viable option.
Not CSS, but inline:
<a href="#"
onmouseover = "this.style.textDecoration = 'none'"
onmouseout = "this.style.textDecoration = 'underline'">Hello</a>
See example →
Rather than needing inline you could use Internal CSS
Google
You could have:
Google
<style>
#gLink:hover {
text-decoration: none;
}
</style>
You could try https://hacss.io:
Google
Demo

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

which one is given more preference for JavaScript or CSS?

here is my code
<!doctype html>
<html>
<head>
<style>
body {
color:red;
}
</style>
<script>
window.onclick = function(){
document.getElementsByTagName("body").color="blue";
}
</script>
</head>
<body>
here is some text for test
</body>
when i run it in my browser (initially it is red) and click in window it doesn't respond to click i mean it should change the color of text from red to blue but nothing happens. Where am i wrong?
Try this:-
Demo
This will add style attribute to the body element, which will override the css rule.
window.onclick = function(){
document.getElementsByTagName("body")[0].style.color="blue";
}
It should be style.color as color is a property of style property of element and even though it is body .getElementsByTagName returns a collection so you need to use document.getElementsByTagName("body")[0] to get the element and apply style to it.
And yes styles applied the element direclty will override the class css rule
Style property has more precedence over styles applied by class.
document.getElementsByTagName("body").color="blue";
This has more preference
Also color is a property of style attribute.
So your style should have looked something like this as getElementsByTagName returns a node list.
document.getElementsByTagName("body")[0].style.color="blue";
it is a better idea to use classes instead, cause it is lot cleaner.
Inline CSS is more powerful and overrides CSS defined anywhere else.As far as working of your code, I modified it a little bit like this:
window.onclick = function(){
//document.getElementsByTagName("body").color="blue";
document.body.style.color="blue";
}
DEMO here
You have an error in your JS. getElementsByTagName returns a NodeList (which is like an array), not a single element. You need to set the property on an element, not a NodeList. For example:
document.body.color="blue";
Setting the color property of the body element (IIRC, it's been a very long time since I went near that part of HTML) is equivalent to setting the color attribute. This is an obsolete presentational hint attribute.
The CSS specification says:
The UA may choose to honor presentational attributes in an HTML source document. If so, these attributes are translated to the corresponding CSS rules with specificity equal to 0, and are treated as if they were inserted at the start of the author style sheet. They may therefore be overridden by subsequent style sheet rules. In a transition phase, this policy will make it easier for stylistic attributes to coexist with style sheets.
So the style specified in the stylesheet should continue to apply.
On the other hand, setting a style.something property is equivalent to modifying the style attribute on an element.
document.body.style.color="blue";
In the cascade, !important declarations aside, properties set via the style attribute are most specific.
So of those two rules, the blue one would win.
JS inserts the changes inline, giving them pretty much the highest priority, unless you have !important in your css.
Check to see if you code (document.getElementsByTagName("body").color="blue";) works from the dev console (F12 for Chrome). There appears to be a problem with it. I can't help debug, however, as I usually do such actions via jQuery, and vanilla JS color changes are unintuitive for me.
js and css does not compete with each other, what you are doing is essentially javascript applying css to an html element, this means that its still css, that type of css is called inline css, . As others have said inline css has more precendence over normal css except if you use !important in your css rules
As to why your code is not working, because you are doing it wrong.
Change
document.getElementsByTagName("body").color="blue";
To
document.getElementsByTagName("body")[0].style.color = 'blue';
Here's a jsFiddle
http://jsfiddle.net/n2kqd/

css style not loaded when window.onload is triggered

Here is my problem : the css style is not initialised when window.onload is triggered.
<div id="foo"></div>
css file
#foo {
height: 200px
}
js file
window.onload = function(){
console.log(document.getElementById('foo').style.height);
};
the console displays : ""
the style must be in a different file, if the style attribute is used (style="height=200px") it works.
.style.height does not show styles that come from CSS rules. It only returns styles that have been explicitly set on that object, either in the HTML or via javascript, not styles inherited from CSS rules.
Instead, you must use window.getComputedStyle(). See the MDN doc for more details on how to use getComputedStyle() properly. Here's one example:
window.getComputedStyle(document.getElementById('foo'),null).getPropertyValue("height");
Note: for older versions of IE, you have to either install a polyfill for getComputedStyle or use el.currentStyle.
Element.style will only be set for inline styles(<div id="foo" style="height: 200px"></div>), to get the computed style use window.getComputedStyle
window.getComputedStyle(document.getElementById("foo"), null).getPropertyValue('height')
You can also consider working with jquery, a very popular javascript libraray with tons of very nice and powerfull features. And if you use the google cdn you don't need to worry about performance cause most browsers will already have the libray in cache.
To get the height of an element you would just use .height() The full explanation is here http://api.jquery.com/height/
Your code would look something like this:
$(document).ready(function() {
console.log($('#foo).height());
});
It may look a bit confusing at first, but you will quickly get the hang of it, and you will be writing js a lot faster and more compact with jquery. I never go without it!
What you really want is either offsetHeight or clientHeight. Try this:
window.onload = function(){
console.log(document.getElementById('foo').offsetHeight);
};

How can I change cssText in IE?

In the past I've been able to modify the CSS on a page via an inline style tag.
I know this sounds horrible but it's for custom CSS writing while working on a kind of WYSIWYG (not with text though).
I used to do something like:
tag.styleSheet.cssText = myrules;
I don't know when exactly, but at some point IE started saying "Invalid Argument" when I try this. The real crux is that doing tag.innerHTML = 'body {}' gives Unable to set value of the property 'innerHTML': object is null or undefined which doesn't happen in any other browser.
EDIT
To be clear I am using an inline style tag. I am not trying to use the inline style attribute.
<style type="text/css" id="mytag"></style>
How can I change the inside of that tag?
EDIT 2
Please see this fiddle:
http://jsfiddle.net/tTr5d/
It appears that my solution of tag.styleSheet.cssText is identical to using styleSheets property. You can comment out the last definition of cssText to see it working as proposed by #Teemu. So now I'm real lost why it's not working in my app. If anyone has ideas what could break that functionality that would be great. In the meantime I'll be tinkering around my app.
IE is limited to 32 stylesheets. I like to forget that fact apparently, which seems to include inline style tags, on top of <link>.
I changed my sandbox to turn on minification so it would put the files together.
Then my code worked.
So it appears that when you go over the limit and insert via JS, you don't get a real error until you try what I did.
You can get a reference to a styleSheet object only via styleSheets collection (or imports collection). If you refer direct to the style element, you'll just get a HTML-element. (Check properties in both objects within simple for..in-loop, and see the difference)
This works in all IEs, and results are rendered immediately:
document.styleSheets['mytag'].addRule('BODY', 'background-color:red');
More info in MSDN: styleSheet object
You can use jQuery. If it's the inline style, you can use the .attr() function.
$("#myElement").attr('style')
otherwise, you can see what .css() has to offer. You can use that to get and set various CSS styles.
Other CSS related jQuery methods
I never had much luck with style elements and IE's innerHTML.
The dom methods are surer, even if you need to branch for IE;
without jquery-
function addNewStyle(str, title){
var el= document.createElement('style');
if(title) el.title= title;
if(el.styleSheet) el.styleSheet.cssText= str;
else el.appendChild(document.createTextNode(str));
document.getElementsByTagName('head')[0].appendChild(el);
return el;
}

Categories

Resources