23

Since IE8 does not support getComputedStyle, we can only use currentStyle. However, it does not return the real "computed" value for some properties.

For example:

<style type="text/css">
#div {/* no properties are defined here */}
</style>
<div id="div">div</div>
// returns "medium" instead of 0px
document.getElementById('div').currentStyle.borderLeftWidth

// returns "auto" instead of 0px
document.getElementById('div').currentStyle.marginLeft

// returns "undefined" instead of 1
document.getElementById('div').currentStyle.opacity

Does anyone have a cross-browser solution for all properties without using jQuery or other Javascript libraries?

user1643156
  • 4,407
  • 10
  • 36
  • 59
  • The IE `currentStyle` object shows you the browser default values for those properties. Perhaps you could use a CSS reset to normalize the defaults across all browsers. – Pointy Mar 31 '13 at 19:10
  • @Pointy I'm looking for a Javascript solution since I'm writing a small library which I don't want it to alter users' styles. – user1643156 Mar 31 '13 at 19:14
  • This [**link**](http://snipplr.com/view/13523/) might help you. – Mr_Green Apr 25 '13 at 12:22
  • @Mr_Green thanks but it doesn't help. I'v seen that page before. The code cannot parse values such as `medium` and `auto` to `px`. – user1643156 Apr 25 '13 at 14:11

5 Answers5

17

Here's a cross-browser function to get a computed style...

getStyle = function (el, prop) {
    if (typeof getComputedStyle !== 'undefined') {
        return getComputedStyle(el, null).getPropertyValue(prop);
    } else {
        return el.currentStyle[prop];
    }
}

You may store it as an utility within an object, or just use it as provided. Here's a sample demo!

// Create paragraph element and append some text to it
var p = document.createElement('p');
p.appendChild(document.createTextNode('something for fun'));

// Append element to the body
document.getElementsByTagName('body')[0].appendChild(p);

// Set hex color to this element
p.style.color = '#999';

// alert element's color using getStyle function
alert(getStyle(p, 'color'));

Check this demo to see it in action:

getStyle = function(el, prop) {
  if (getComputedStyle !== 'undefined') {
    return getComputedStyle(el, null).getPropertyValue(prop);
  } else {
    return el.currentStyle[prop];
  }
}

// Create paragraph element and append some text to it
var p = document.createElement('p');
p.appendChild(document.createTextNode('something for fun'));

// Append element to the body
document.getElementsByTagName('body')[0].appendChild(p);

// Set hex color to this element
p.style.color = '#999';

// alert element's color using getStyle function
console.log(getStyle(p, 'color'));
p {
  color: red;
}
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Gabriel kyabu
  • 187
  • 1
  • 2
  • This will fail for a prop like `backgroundColor` because `getPropertyValue` expects the CSS property name, but the `currentStyle` has it as the camel-case version. A one-liner replacement: `return (typeof getComputedStyle !== 'undefined' ? getComputedStyle(el, null) : el.currentStyle)[prop];` – Emile Bergeron Dec 28 '16 at 03:03
  • 1
    This doesn't answer the question. Question asks for cross-browser solution for "all properties", even the ones mentioned in the question where "currentStyle" doesn't return the real computed values. – blissfool May 17 '17 at 21:17
7

You don't want to use jquery but there's nothing preventing you from peeking into the code and see how they dealt with it :-)

Inside jquery code there's a reference about this comment which seems to the point (read also the whole article). Here's the jquery code that should deal with your problem:

else if ( document.documentElement.currentStyle ) {
    curCSS = function( elem, name ) {
        var left, rsLeft,
            ret = elem.currentStyle && elem.currentStyle[ name ],
        style = elem.style;

    // Avoid setting ret to empty string here
    // so we don't default to auto
    if ( ret == null && style && style[ name ] ) {
        ret = style[ name ];
    }

    // From the awesome hack by Dean Edwards
    // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291

    // If we're not dealing with a regular pixel number
    // but a number that has a weird ending, we need to convert it to pixels
    // but not position css attributes, as those are proportional to the parent element instead
    // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
    if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {

        // Remember the original values
        left = style.left;
        rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;

        // Put in the new values to get a computed value out
        if ( rsLeft ) {
            elem.runtimeStyle.left = elem.currentStyle.left;
        }
        style.left = name === "fontSize" ? "1em" : ret;
        ret = style.pixelLeft + "px";

        // Revert the changed values
        style.left = left;
        if ( rsLeft ) {
            elem.runtimeStyle.left = rsLeft;
        }
    }

    return ret === "" ? "auto" : ret;
};
}
  • 1
    In case anyone else is wondering, `rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" );`. The full standalone source can be found here: http://stackoverflow.com/questions/17884653/ – Beejor Jul 27 '15 at 07:29
7

instead of :

getComputedStyle !== 'undefined'

it should be :

typeof getComputedStyle !== 'undefined'

otherwise it would never works.

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Eugen Mihailescu
  • 3,553
  • 2
  • 32
  • 29
4

This will not work for all styles but will work for dimensions (which is what I needed).

Instead of trying to guess what styles are applied, simply use the position in pixels of each of the four sides of a box-like element to calculate the dimensions. This will also work back to IE 5 and FF 3.

height = elem.getBoundingClientRect().bottom - elem.getBoundingClientRect().top;
width = elem.getBoundingClientRect().right - elem.getBoundingClientRect().left;

See also: getBoundingClientRect is awesome

If this still doesn't work for you, check out this fiddle I put together for calculating the inside width of a box. It uses the following as a shim for getComputedStyle:

/**
 * getComputedStyle function for IE8
 * borrowed from:
 * http://missouristate.info/scripts/2013/common.js
 */
"getComputedStyle" in window || function() {
  function c(a, b, g, e) {
    var h = b[g];
    b = parseFloat(h);
    h = h.split(/\d/)[0];
    e = null !== e ? e : /%|em/.test(h) && a.parentElement ? c(a.parentElement, a.parentElement.currentStyle, "fontSize", null) : 16;
    a = "fontSize" == g ? e : /width/i.test(g) ? a.clientWidth : a.clientHeight;
    return "em" == h ? b * e : "in" == h ? 96 * b : "pt" == h ? 96 * b / 72 : "%" == h ? b / 100 * a : b;
  }
  function a(a, c) {
    var b = "border" == c ? "Width" : "", e = c + "Top" + b, h = c + "Right" + b, l = c + "Bottom" + b, b = c + "Left" + b;
    a[c] = (a[e] == a[h] == a[l] == a[b] ? [a[e]] : a[e] == a[l] && a[b] == a[h] ? [a[e], a[h]] : a[b] == a[h] ? [a[e], a[h], a[l]] : [a[e], a[h], a[l], a[b]]).join(" ");
  }
  function b(b) {
    var d, g = b.currentStyle, e = c(b, g, "fontSize", null);
    for (d in g) {
      /width|height|margin.|padding.|border.+W/.test(d) && "auto" !== this[d] ? this[d] = c(b, g, d, e) + "px" : "styleFloat" === d ? this["float"] = g[d] : this[d] = g[d];
    }
    a(this, "margin");
    a(this, "padding");
    a(this, "border");
    this.fontSize = e + "px";
    return this;
  }
  b.prototype = {};
  window.getComputedStyle = function(a) {
    return new b(a);
  };
}();
Kyle Falconer
  • 8,302
  • 6
  • 48
  • 68
4

This was too big for an edit, so it was made an answer but it doesn't provide a full answer to the question at hand.


Gabriel's answer fails with a property like "backgroundColor" or "background-color" depending on the browser version because .getPropertyValue expects the CSS property name and el.currentStyle[prop] needs the camel-case version.

Here's a fixed version which always expects the camel-case version:

function getStyle(el, prop) {
    return (typeof getComputedStyle !== 'undefined' ?
        getComputedStyle(el, null) :
        el.currentStyle
    )[prop]; // avoid getPropertyValue altogether
}
Community
  • 1
  • 1
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • This doesn't answer the question though. You've merely fixed another answer which also doesn't answer the question. – blissfool May 17 '17 at 21:15
  • @blissfool it does answer the part about a **cross-browser equivalent for `getComputedStyle`** which myself and a lot of other people seem to be looking for (based on upvotes). While you have the right to not like my answer, it was too big for an edit and it could help someone who comes across this question in the future, so I don't think it deserves a downvote. – Emile Bergeron May 17 '17 at 21:37
  • 1
    Technically, the question was not asking about "cross-browser equivalent for getComputedStyle". Well, it was, but it was asked in a way that it should also return the correct values all the time. The question wasn't phrase too clearly at the end but that was the context. They already knew they needed to use getComputedStyle or currentStyle. – blissfool May 18 '17 at 16:49
  • 1
    I do agree that it could be helpful for people who happens upon this question and was going to change my vote but it seems to be locked due to the amount of time that passed. I will change my vote if you want to make any slight edit. – blissfool May 18 '17 at 16:50
  • @blissfool I added a disclaimer to explain why this answer exist. This should let you adjust the vote if you still want. – Emile Bergeron May 18 '17 at 17:11