Cross-browser (IE8-) getComputedStyle with Javascript?

24,078

Solution 1

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;
};
}

Solution 2

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;
}

Solution 3

instead of :

getComputedStyle !== 'undefined'

it should be :

typeof getComputedStyle !== 'undefined'

otherwise it would never works.

Solution 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);
  };
}();

Solution 5

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
}
Share:
24,078

Related videos on Youtube

user1643156
Author by

user1643156

Updated on May 19, 2020

Comments

  • user1643156
    user1643156 almost 4 years

    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?

    • Pointy
      Pointy about 11 years
      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.
    • user1643156
      user1643156 about 11 years
      @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.
    • Mr_Green
      Mr_Green about 11 years
      This link might help you.
    • user1643156
      user1643156 about 11 years
      @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.
  • Beejor
    Beejor almost 9 years
    In case anyone else is wondering, rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" );. The full standalone source can be found here: stackoverflow.com/questions/17884653
  • Emile Bergeron
    Emile Bergeron over 7 years
    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];
  • blissfool
    blissfool almost 7 years
    This doesn't answer the question though. You've merely fixed another answer which also doesn't answer the question.
  • blissfool
    blissfool almost 7 years
    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.
  • Emile Bergeron
    Emile Bergeron almost 7 years
    @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.
  • blissfool
    blissfool almost 7 years
    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
    blissfool almost 7 years
    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.
  • Emile Bergeron
    Emile Bergeron almost 7 years
    @blissfool I added a disclaimer to explain why this answer exist. This should let you adjust the vote if you still want.