15

HTML:

<div id="test">This is a test</div>

JavaScript:

var elem = document.getElementById('test');

elem.style.setProperty('color', 'green', 'important');
elem.style.color = 'red';

Live demo: http://jsfiddle.net/4fn6h/3/

The text is green in Chrome, Safari, and IE9, but red in Firefox, and Opera. (Also, the text is black in IE7, and IE8, because the code throws an error, but let's ignore that... )

So, which browsers follow the standard here? Should it be possible to override a setProperty(...,'important') or not?

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • See this question: http://stackoverflow.com/questions/462537/overriding-important-style-using-javascript – Diodeus - James MacFarlane May 22 '12 at 20:12
  • http://quirksmode.org/dom/w3c_css.html#t46 – jbabey May 22 '12 at 20:13
  • interesting, this also happen with http://jsfiddle.net/4fn6h/4/ – ajax333221 May 22 '12 at 20:16
  • @Diodeus That thread didn't help `:(` – Šime Vidas May 22 '12 at 20:18
  • @jbabey That link didn't help `:(` – Šime Vidas May 22 '12 at 20:20
  • 1
    Sure seems to me like Firefox's behavior would be preferred. A property can't have two values, right? – cliffs of insanity May 22 '12 at 20:24
  • @cliffsofinsanity I assume that Chrome/Safari/IE9 treat a property with an `!important` value as read-only, so it cannot be overwritten, so they just disregard the second assignment... – Šime Vidas May 22 '12 at 20:27
  • 1
    @cliffsofinsanity But the problem is: which style should take effect, the one that was assigned last or the one with the highest priority? – Evan Mulawski May 22 '12 at 20:29
  • @EvanMulawski: But there's only one style. It's just that its value is being changed. At least that's how I would imagine it would be interpreted. – cliffs of insanity May 22 '12 at 20:31
  • @cliffsofinsanity He probably meant "value", not "style"... – Šime Vidas May 22 '12 at 20:32
  • @ŠimeVidas: I'm guessing the opposite, that Chrome and the others make the value readonly when the style is marked as important. That wouldn't seem like a reasonable expectation. – cliffs of insanity May 22 '12 at 20:32
  • @cliffsofinsanity But that's what I said `:)`. If the value has the "important" flag set, the property becomes read-only. – Šime Vidas May 22 '12 at 20:33
  • @ŠimeVidas: Yeah, I just realized I had misinterpreted your comment. :) – cliffs of insanity May 22 '12 at 20:33
  • 5
    ...in any case, it doesn't seem like a reasonable approach to make "important" such that it's current value is more important than a future value on the same element. Seems that "important" should only affect cascading. – cliffs of insanity May 22 '12 at 20:35
  • ...Chrome behaves like Firefox if you don't change approaches in the assignment. http://jsfiddle.net/4fn6h/7/ So Chrome indeed does seem to see `elem.style.color...` as inferior to `elem.style.setProp...` – cliffs of insanity May 22 '12 at 20:39
  • @cliffsofinsanity `elem.style.color = ...` is inferior because the priority flag cannot be set with it. If you "turn off" the priority in `setProperty()`, it won't have effect in Chrome: http://jsfiddle.net/4fn6h/10/ *** Wait a minute... Why is the color blue in Firefox? – Šime Vidas May 22 '12 at 20:46
  • 2
    So Chrome won't let you revert importance once set. Well that's just great... Firefox should be blue, because the local "important" on the element has been set to `null`, and the stylesheet one now takes priority. – cliffs of insanity May 22 '12 at 20:48
  • @cliffsofinsanity Ah yes. This means that Firefox is doing it right. – Šime Vidas May 22 '12 at 20:51
  • @ŠimeVidas: Yes, it's approach seems most reasonable. I'd consider the others to be buggy. – cliffs of insanity May 22 '12 at 20:52
  • So, we can basically forget about `setProperty(...,'important')` since it's not cross-browser `:(` – Šime Vidas May 22 '12 at 20:53
  • @ŠimeVidas: Seems that a workaround in Chrome is to use `.removeProperty()` before setting the new value. http://jsfiddle.net/4fn6h/12/ – cliffs of insanity May 22 '12 at 20:54
  • Target Chrome and others with some feature detection, and this fix seems to work. http://jsfiddle.net/4fn6h/15/ ...oh, you'll need to encorporate `getPropertyPriority` so that it doesn't wipe out the priority when one is not sent in the update. – cliffs of insanity May 22 '12 at 21:00
  • @cliffsofinsanity Wait a minute... What has more priority than a value set inline? Nothing, right? Then, what's the point of having the priority as a third parameter of `setProperty`? I mean, if `!important` is really only for cascade, and if `setProperty` sets the property inline, then there is no point. I am talking about Chrome here. Firefox does it right and `setProperty(...,'important')` and `setProperty(...,null)` behave differently. – Šime Vidas May 22 '12 at 21:06
  • 2
    Except that an "!important" in a stylesheet overrides the inline style. I assume that's the reason for having "important" available directly on the element. ...wait, maybe I'm misunderstanding again. – cliffs of insanity May 22 '12 at 21:13
  • @cliffsofinsanity Uh, my last question is not correct. Of course, an !important value in the CSS file has more priority than a regular inline value. This is a good example of how Chrome is doing it wrong - in the 10. demo (http://jsfiddle.net/4fn6h/10/), the text color should be blue (because the "blue" value is !important), but it's green in Chrome (even though we removed the !important flag from the inline value). I'm not 100% sure, though... – Šime Vidas May 22 '12 at 21:14
  • Right, that's where removing the property entirely before setting its new value seems to be the only way for Chrome to emulate what we assume to be a correct behavior. Once Chrome sees "important", that style property basically locked down permanently unless destroyed. – cliffs of insanity May 22 '12 at 21:20
  • 1
    ...then there's the unfortunate fact of Firefox requiring all 3 arguments. Seems like a general fix could be used to overcome all these issues. – cliffs of insanity May 22 '12 at 21:22
  • @cliffsofinsanity Yes, a cross-browser function. That's usually what jQuery does. However, not in this case (since it doesn't recognize `!important`). – Šime Vidas May 22 '12 at 21:29
  • possible duplicate: http://stackoverflow.com/questions/6129304/important-overridden – gopi1410 May 24 '12 at 04:38
  • @cliffsofinsanity, `!important` does not make it read only. user css with `!important` should override `!important` in author css. this is done for accessibility over control. user reading the content should have the absolute power to change how the content is presented. – Ray Cheng May 24 '12 at 05:04

3 Answers3

2

The spec is not clear. There are two ways to look at it:

  1. it's a bug in WebKit/IE9. If you are overwriting the color value, there is no reason for the old value to stay around, important or not.
  2. WebKit/IE9 are correct. The DOM interface style manipulates the style property of the element, which is considered a CSS Declaration Block. In a CSS block, a property with !important set will always take precedence over ones without. By that rule the change to 'red' should have no effect, so it's effectively ignored.

I believe the latter is the most likely explanation. Consider having a declaration like this:

p { color: red !important; }

If you add a second color rule, without !important, it has no effect:

p {
  color: red !important;
  color: blue;
}
/* the color is still red */

The same applies to manipulating the HTML style attribute directly.

So the behavior in Chrome/Safari/IE9 is consistent with the CSS cascading rules, while FF and Opera are treating DOM style as a simple object without regard for the cascading rules, not as an interface to the CSS declarations.

http://www.w3.org/TR/2000/REC-DOM-Level-2-Style-20001113/css.html#CSS-CSSStyleDeclaration


Fun fact: webkit seems to be doing a string match for important, so this works too:

elem.style.setProperty('color', 'red', 'this is a really important rule');

And a tip: pick a better color pair next time, you're making it hard for the color blind to help :)

Nikola K.
  • 7,093
  • 13
  • 31
  • 39
Ricardo Tomasi
  • 34,573
  • 2
  • 55
  • 66
  • `!` is a delimiter and `important` is a keyword. delimiter is designed for browsers to parse through the styles. `important` is the "operation" should be performed. `super` or `very` are not part of any w3 standard and we developers should never use them. let's be clear and loud. – Ray Cheng May 24 '12 at 04:45
  • @RayCheng do you see the word "curiosity" up there? I just found that funny. Also, the `priority` argument for `setProperty` shouldn't include the `!`, but the function accepts `setProperty('color', 'red !important', null)` too (webkit at least). – Ricardo Tomasi May 24 '12 at 08:15
0

It could be that Firefox and Opera's behavior is more appropriate.

When you issue elem.style.color = 'red'; you did not turn off the "important" priority on the color, in which case it would make sense to change the color to red. As far as why they choose to do it one way or another, I don't know.

Dave
  • 4,949
  • 6
  • 50
  • 73
  • 1
    One possibility is that FF/Opera simply overwrite the entire `color` property. Just because the old value had `!important` doesn't mean that the property was read-only. But then why don't Chrome/Safari/IE9 overwrite it too? – Šime Vidas May 22 '12 at 20:25
  • There's nothing about that in the specification. What happens in Chrome/Safari/IE9 when the priority is set (like in http://jsfiddle.net/4fn6h/9/)? – Bergi May 22 '12 at 20:39
  • Maybe they never considered, or concerned themselves with the possibility developers might access the color in two different ways, style.color and style.setProperty, so did not feel compelled to address this inconsistency. Maybe they anticipated development environments would have certain conventions of their own. I don't know if these techniques normally intermingle in JavaScript libraries. – Dave May 22 '12 at 20:57
  • @Šime Vidas, `!important` can overrides normal css. normal css should never override `!important` css. the only time `!important` css gets overridden is when both user and author css contains `!important` and user css takes precedence. please see my post for details. – Ray Cheng May 24 '12 at 04:56
0

Should it be possible to override a setProperty(...,'important') or not? yes it should. but you have to do it with another ele.style.setProperty call. take a look at this and you should see red in all modern browsers.

So, which browsers follow the standard here? since green is set with !important, it should not be replaced with red since red is not set with !important. that means chrome, safari and IE9 are following the standard and firefox is NOT.

Ray Cheng
  • 12,230
  • 14
  • 74
  • 137
  • This is all correct, but you forgot that the issue at hand is the DOM interface for modifying style declarations, not just CSS. This behavior is opposite to direct manipulation of the `style` property, which doesn't allow for `!important` to be set. – Ricardo Tomasi May 24 '12 at 08:18