使用Javascript获取跨浏览器(IE8及以下版本)的计算样式?

23

IE8不支持getComputedStyle,因此我们只能使用currentStyle。但对于某些属性,它并不返回真正的“computed”值。

例如:

<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

有没有跨浏览器的解决方案可以不使用jQuery或其他JavaScript库来处理所有属性?


IE的currentStyle对象可以显示浏览器对这些属性的默认值。也许您可以使用CSS重置来规范化所有浏览器的默认值。 - Pointy
@Pointy 我正在寻找一个JavaScript解决方案,因为我正在编写一个小型库,我不希望它改变用户的样式。 - user1643156
这个链接可能会对你有所帮助。 - Mr_Green
@Mr_Green 谢谢,但是它并没有帮助到我。我之前已经看过那个页面了。这段代码无法将 mediumauto 等值解析为 px - user1643156
5个回答

17

这里是一个用于跨浏览器获取计算样式的函数...

getStyle = function (el, prop) {
    if (typeof 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
alert(getStyle(p, 'color'));

查看此演示以查看它的实际效果:

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


这段代码对于 backgroundColor 这样的属性会失败,因为 getPropertyValue 函数期望传入 CSS 属性名,但是 currentStyle 中存储的是驼峰式命名的版本。可以使用一行代码替换:return (typeof getComputedStyle !== 'undefined' ? getComputedStyle(el, null) : el.currentStyle)[prop]; - Emile Bergeron
1
这并没有回答问题。问题要求跨浏览器解决方案,包括问题中提到的“所有属性”,即使在“currentStyle”不能返回真实计算值的情况下也要解决。 - blissfool

7

替代:

getComputedStyle !== 'undefined'

应该是:

typeof getComputedStyle !== 'undefined'

否则它永远不会起作用。

7

您不想使用jquery,但是没有什么阻止您查看代码并查看他们如何处理它 :-)

在jquery代码中,有一个关于这个评论的引用,似乎很重要(也请阅读整篇文章)。 以下是应该解决您问题的jquery代码:

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
如果有其他人也在疑惑,那么 rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" );。完整的独立源代码可以在这里找到: https://dev59.com/0nTYa4cB1Zd3GeqP0fHY - Beejor

4

这种方法并不适用于所有的样式,但对于尺寸(这就是我所需要的)有效。

不要试图猜测应用了哪些样式,只需使用类似盒子的元素的四边像素位置来计算其尺寸即可。这也适用于IE 5和FF 3及以上版本。

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

相关阅读:getBoundingClientRect非常棒

如果这对您仍然不起作用,请查看我为计算框内宽度而准备的此示例。它将下面的代码用作getComputedStyle的shim:

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

4

由于篇幅过大,这篇文章被制成了答案,但它并没有提供完整的解决方案。


Gabriel的解答在属性为"backgroundColor""background-color"时会失败,这要取决于浏览器的版本,因为.getPropertyValue需要CSS属性名称,而el.currentStyle[prop]需要驼峰式命名的版本。

下面是一个修复过的版本,它总是期望驼峰式的版本:

function getStyle(el, prop) {
    return (typeof getComputedStyle !== 'undefined' ?
        getComputedStyle(el, null) :
        el.currentStyle
    )[prop]; // avoid getPropertyValue altogether
}

这并没有回答问题。你只是纠正了另一个同样没有回答问题的答案。 - blissfool
@blissfool,它确实回答了关于getComputedStyle跨浏览器等效方法的部分,我和很多其他人似乎都在寻找这个(基于赞数)。虽然您有权不喜欢我的答案,但它太大了无法编辑,并且它可能会帮助将来遇到这个问题的人,因此我认为它不应该被投票否决。 - Emile Bergeron
1
从技术上讲,这个问题并没有询问“getComputedStyle的跨浏览器等效方法”。嗯,它确实是这样,但是问题的提出方式应该也能始终返回正确的值。虽然问题结尾的措辞不太清晰,但这就是上下文。他们已经知道需要使用getComputedStyle或currentStyle。 - blissfool
1
我同意这可能对那些偶然遇到这个问题的人有所帮助,而且我本来也打算改变我的投票,但由于时间过去太久,似乎已经被锁定了。如果你想进行任何轻微的编辑,我会改变我的投票。 - blissfool
@blissfool,我添加了一份免责声明来解释为什么这个答案存在。如果你仍然想要,这应该让你调整投票。 - Emile Bergeron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接