Computed vs Cascaded Style 30

Most JS frameworks and libraries I’ve seen have a function similar to this:

function getStyle(el, prop) {
  if (document.defaultView && document.defaultView.getComputedStyle) {
    return document.defaultView.getComputedStyle(el, null)[prop];
  } else if (el.currentStyle) {
    return el.currentStyle[prop];
  } else {
    return el.style[prop];
  }
}

So what is wrong with this you might ask? Lets add some background and then
we can get back to that question.

Computed Style

Computed style represents the actual computed value of a style in absolute
units. For example ’100px’ (for width) or ‘left’ (for text-align). The computed
value is never ‘auto’, ‘inherit’, ’50%’, ‘smaller’, ’1.5em’ etc. These values are
relative to something and the browser needs to convert these values to absolute
values first.

Cascaded Style

Cascaded style is the real style value that is applied to an element when the
style value is set to ‘inherit’. Inherit means that it should get its value from
the first ancestor that has a non ‘inherit’ value. A few CSS properties have
their value set to ‘inherit’ by default. Most common of these are probably
‘color’ and ‘font-size’. If you change the font size of a paragraph you want the
links in the paragraph to change their font size as well.

Inline Style

Inline style is the style value you have added to the style attribute on you
element or the style properties you have set in script using
element.style.propertyName.

Example

<style>

div {
  width: 500px;
  font-size: 12px;
}

p {
  width: 50%;
  font-size: 1em;
}

a {
  font-size: inherit;
}

</style>

<div>
<p>Some text with <a id=a href=#>a link</a>.
More <b style="font-size:150%">text</b></p>
</div>
Computed Style Cascaded Style Inline Style
p width “250px” “50%” “”
p fontSize “12px” “1em” “”
a fontSize “12px” “1em” “”
b fontSize “18px” “150%” “150%”

Browser Support

All browsers except IE has a way to get the computed style. The way to do
this is to use document.defaultView.getComputedStyle. Only IE has a way to get
the cascaded style. This is done using element.currentStyle.

All browsers supports getting the inline style (even IE4) but inline style is
not that interesting because it is empty unless you already set it, and in that
case you don’t really need to query it.

Conclusion

Back to our earlier question. What is wrong with our getStyle function? It
should be pretty obvious now. It will give very different and sometimes
unexpected results depending both on browsers and on the value set by the page
author and even worse, set by user style sheets.

So how do we solve this? We stop supporting IE of course… seriously, with
the market share IE has that is not an option. The best solution is to remove
functions like these from shared code and instead add more specific functions.
One can for example, often calculate the computed value based on the cascaded
value and the ancestors. A good example of that is ‘visibility’. Computing that
is pretty easy. If the value is ‘inherit’ check the parents until a non inherit
value is found. For things like left, width etc you will be better of using
offsetLeft, offsetWitdh etc. There are a lot of cases and sometimes it is just
not possible (or requires iterative testing with different absolute sized
elements).

Comments

Override style

There is one more style type that is worth mentioning and that is the
override style. This is called document.defaultView.getOverrideStyle in the W3C
DOM and element.runtimeStyle in IE. It allows you to override the style property
in such a way that it has (a) highest priority and (b) not serialized from the
DOM when you do things like cssText and innerHTML. getOverrideStyle is not
supported in Gecko so it is still only useful to IE specific code.

It is a bit strange to me that the W3C DOM never added a way to get the
cascaded style. The usecases for this are few but they do exists.

What is even more strange is that MS did not realize the need for a way to
get the compouted style back in the days when they believed in Trident as a
platform.

  • http://dean.edwards.name/ Dean Edwards

    This works on IE6 and IE7:

    var PIXEL = /^\d+(px)?$/i;
    function getPixelValue(element, value) {
    if (PIXEL.test(value)) return parseInt(value);
    var style = element.style.left;
    var runtimeStyle = element.runtimeStyle.left;
    element.runtimeStyle.left = element.currentStyle.left;
    element.style.left = value || 0;
    value = element.style.pixelLeft;
    element.style.left = style;
    element.runtimeStyle.left = runtimeStyle;
    return value;
    };

  • yn

    I disagree. I find currentStyle much more useful than getComputedStyle and would have preferred non-IE browsers to implement it instead of computed styles (ideally both).

    There is always a way to calculate the pixel value using the tools browsers provide. But in FF today, there simply NO WAY to know whether a width value is set in percentages, inches or pixels if the value had been set outside of the style attribute! This is a pretty unbelievable shortcoming.

    The offset* and client* functions provide nearly everything you may want in terms of getting the pixel values, and the difference between them helps you calculate padding/border values. In fact they’re so useful that I’ve rarely seen anyone opt for computed style in such situations, even if the target is FF-only.

  • http://erik.eae.net Erik Arvidsson

    Dean: That seems to work pretty well in some cases. Which cases? It seems like it would only work for properties that have pixel* equivalent (left, top, right, bottom, width and height).

    yn: How would you compute the font size given the following:

    * { font-size: 12pt; }

    or the background color given:

    * { background-color: Highlight; }

  • Pingback: All in a days work…

  • yn

    Erik: It’s not about finding cases where offset* and client* won’t be enough, they certainly exist. It’s about what’s more useful to have if you had to choose one. Why would you need the pixel value of a font set in points? I really can’t think of such a scenario. If you want the height of the line in pixels, which would make more sense, that’s easy to do.

    On the other hand, I can easily think of multiple scenarios requiring the actual cascaded properties and I’ve been constantly bumping against these cases, as mentioned above.

    Btw, to answer your specific questions:

    function getRealBackgroundColor(el) {
    var oRG=document.body.createTextRange();
    oRG.moveToElementText(el);
    var iClr=oRG.queryCommandValue(“BackColor”);
    return “rgb(“+(iClr & 0xFF)+”,”+((iClr & 0xFF00)>>8)+”,”+((iClr & 0xFF0000)>>16)+”)”;
    }

    Your other question was already answered by Dean, his function can take any value in any unit (except % in some cases) and return it in pixels, it’s not limited to .left, he’s just using it to do the conversion. so getPixelValue(document.body,”12pt”) will give you the pixel value for your font under your setup.

    Again, I’m not saying anything everywhere can be converted to an absolute value, I’m just saying that currentStyle is a lot more useful.

  • http://erik.eae.net Erik Arvidsson

    yn: Thanks, the queryCommandValue is a great example how to do this.

  • Papandreou

    @yn: Your getRealBackgroundColor function is really interesting. For different reasons, I’ve been looking for a way to get the rrggbb values corresponding to a user’s CSS system colors, but I actually gave up a while ago.

    However, I can only get your code to work in IE. Any chance you know a cross-browser way of accomplishing this?

  • yn

    Papandreou: In any other browser it’s trivial to get the real background color, via getComputedStyle. IE is the only one that makes this a bit of a challenge.

    To create a cross-browser function simply check if the getComputedStyle method exists (FF, Opera, etc.), and if so use it, otherwise see if the createTextRange method exists (IE), and if so use it.

    A *real* challenge would be to get the cascaded value (“red”, “highlight”, etc.) set in external CSS in Firefox.

    BTW, Erik: Your article is mistaken. Opera supports .currentStyle properly, allowing you to get the cascaded style (from the article: “Only IE has a way to get the cascaded style.”).

  • Pingback: Links for 8/6/07 [my NetNewsWire tabs]

  • http://glazkov.com/ Dimitri Glazkov

    Another interesting tidbit is that computed style does not take into account margin collapse. For instance, the marginTop value reported does not necessarily represent the actual margin value in effect. Quick example:

    Yo

    Using just default styles, the computed style on body will be 8, but it’s not very useful, because the effective margin is 21 (body margin collapsed in favor of h1).

  • http://glazkov.com/ Dimitri Glazkov

    Sorry, I should’ve escaped the markup:

    <body>
    <div>
    <h1>Yo</h1>
    </div>
    </body>

  • Melikoth

    For some reason when I use this it returns “auto” for top and left values. The object I am interrogating has no styling applied, but I was hopinh it would tell me where it was located.

  • xErath

    Why all the trouble of defining document.defaultView.document.defaultView.document.defaultView.document.defaultView.document.defaultView ??

    use .getComputedStyle directly

  • http://www.counti.org Michel

    Stylesheets are class. It reduces size doe this is a page of search engines thus can better spiders. What a shame I only think that the Internet Explorer and Firefox that partially distinct process.

  • Pingback: Things you should know when not using a JS library « Lea Verou

  • Bill

    @Dean Edwards: the code provided does not work properly under the following conditions in IE7 (I haven’t tried it in IE6).

    Create a CSS rule body { font-size: 62.5%; }

    Somewhere on a page, put some text in the body of a SPAN tag.

    Your code will return 625px. NOT cool! :(

  • http://www.strictly-software.com Rob

    I had a similar problem the other day requiring the computed style in px not the currentStyle or style value and ran into the limitations of Deans hack when working with styles using %. The following function seems to correctly convert the style to px and ems and also handles styles in % and child elements where the parent is in % but the child is set to “auto”. It returns an object with the style value (computed/current), size in px, sixe in em, size 1em equates to in px on that element. May not be perfect but seems to work at the moment until told otherwise :)

    http://www.strictly-software.com/CSSStyleObject.asp

  • http://www.tomus.eu/ Tomek

    Very nice solution.
    But there is a little bug in the hack by Dean Edwards.
    I had a case where floating point numbers had to pass this hack.
    It return false :( this was logical :P
    i’ve modified this hack to

    if ( !/^\d+(.\d*)+(px)?$/i.test( ret ) ){

    // do something good :)

    }
    have fun i hope i could help someone

  • Pingback: Dean Edwards: Convert any colour value to hex in MSIE

  • Pingback: 超酷带纹理网页滚动条效果 « 酷码资源–帮助你收集一些常用、经典、不易记的代码与技巧 PHP代码 ASP代码 精选JS代码 WORDPRESS 网站SEO Flash焦点广告 JS焦点广告 CSS技巧

  • Pingback: Convert any colour value to hex in MSIE « DesignerLinks

  • Lindsey

    I know you guys may just think anyone that doesn’t have the capability of learning computer systems and hacking via code or html might just be suckers, I really hope you haven’t hacked my computer :( I saw something in my files that deeply disturbed me and I was hoping someone could help me figure out if it was a practical joke or really a virus. Because it’s not funny if it is a virus….but I am willing to laugh at the cleverly of putting something in the encoding of your “virus” that brings me to this website…. so love me, hate me whatever…

    ~Lindsey

  • http://www.ekoal.com Bitkisel Ürünler

    !’wOw’! Thank you very too much…

  • http://www.altincilek.tk altın çilek

    For some reason when I use this it returns “auto” for top and left values. The object I am interrogating has no styling applied, but I was hopinh it would tell me where it was located.

  • Pingback: Let’s Make a Framework: CSS Manipulation | tips & tricks

  • Pingback: js现实网页滚动条效果 | 宝典网

  • Pingback: Computed vs Cascaded Style | Neekey的个人小博客

  • Pingback: Styles and classes, getComputedStyle | ss's space

  • Dan

    I found code inside jQuery based on this “solution”. Has anyone thought that for a TOP, for example, we shouldn’t use left & pixelLeft for figuring out the actual value? I have a css with LEFT and TOP of 10% and go figure, they end up having the same value when using the CSS function, when obviously the parent isn’t a square.

    Unbelievable that this code made it into jQuery as it is.

  • http://www.3code.cn wordpress themes

    I found code inside jQuery based on this “solution”. Has anyone thought that for a TOP, for example, we shouldn’t use left & pixelLeft for figuring out the actual value? I have a css with LEFT and TOP of 10% and go figure, they end up having the same value when using the CSS function, when obviously the parent isn’t a square.

    Unbelievable that this code made it into jQuery as it is.