获取元素CSS值之getComputedStyle方法熟悉

这篇文章发布于 2012年05月8日,星期二,23:31,归类于 JS API。 阅读 356610 次, 今日 55 次 97 条评论

 

一、碎碎念~前言

我们都用过jQuery的CSS()方法,其底层运作就应用了getComputedStyle以及getPropertyValue方法。

对于那些只想混口饭吃的人来讲,晓得CSS()如何使用就足够了。对于希望在JS道路上越走越远的来人说,简单了解一些JS库底层实现对自己的学习很有帮助。可能谈不上信手拈来的使用,至少对创造一些创意新颖的新技术拓宽了思路。

jQuery为何受欢迎,其中原因之一就是方法名称比较短。好比打架一样,块头大的潜意识认为厉害,就不由得心生畏惧,退避三舍;小个子(或村妇,小孩)嘛,自然以为是软豆腐,愿意接受作为对手。
功夫剧照 周星驰被村妇K 张鑫旭-鑫空间-鑫生活 功夫剧照 周星驰找小孩单挑 结果…… 张鑫旭-鑫空间-鑫生活

因此,当看到类似getComputedStyle这么长的方法名的时候,我们身体里那个懒惰小人突然就醒了:哎哟哟,这东西,就跟放心食品一样,几年才见一回。看上去又蛮复杂,想到晚上还要跟妹子聊天。这东西,就让它从旁边过吧,反正不会掉块肉的。

网上不是有这么个段子嘛:可怕的是,比你聪明的人比你更勤奋。那么,这里的“勤奋”的差异体现在什么地方呢?就拿这个getComputedStyle举例:懒惰青年是看一下,立马像看见凤姐一样视线离开;普通青年是看一下,发现自己不了解,百一下或谷一下,熟悉了解之;勤奋青年是不仅了解,还抽出时间实践之(如做个简单demo测试),熟悉方法的特异性,验证一些观点正确性。

您可以按照你现在的心理状态看看你是哪类青年:如果此时,您已经对本文的内容没有兴趣了(当然,您的工作与JS关系亲密),您是……(你懂的);如果您看完本文内容,发现,还是有不少收获,心中回味下,然后ctrl+w去其他地方觅食,不再回来,那您是普通青年;如果您看完本文,然后对所说的一些内容作了额外的测试,例如IE9浏览器是否支持测试等,并通过评论形式指出可能的错误,不得不说您是勤奋青年,假以时日,必有一番技术作为。从我文章的些评论来看,有不少同行就是这样的勤奋人儿。

の, 好久没写文章,话又多了,打住,进入正题。

二、getComputedStyle是?

getComputedStyle是一个可以获取当前元素所有最终使用的CSS属性值。返回的是一个CSS样式声明对象([object CSSStyleDeclaration]),只读。

getComputedStyle() gives the final used values of all the CSS properties of an element.

语法如下:

var style = window.getComputedStyle("元素", "伪类");

例如:

var dom = document.getElementById("test"),
    style = window.getComputedStyle(dom , ":after");

就两个参数,大家都懂中文的,没什么好说的。只是额外提示下:Gecko 2.0 (Firefox 4 / Thunderbird 3.3 / SeaMonkey 2.1) 之前,第二个参数“伪类”是必需的(如果不是伪类,设置为null),不过现在嘛,不是必需参数了。

三、getComputedStyle与style的区别

我们使用element.style也可以获取元素的CSS样式声明对象,但是其与getComputedStyle方法还有有一些差异的。

  1. 只读与可写
    正如上面提到的getComputedStyle方法是只读的,只能获取样式,不能设置;而element.style能读能写,能屈能伸。
  2. 获取的对象范围
    getComputedStyle方法获取的是最终应用在元素上的所有CSS属性对象(即使没有CSS代码,也会把默认的祖宗八代都显示出来);而element.style只能获取元素style属性中的CSS样式。因此对于一个光秃秃的元素<p>getComputedStyle方法返回对象中length属性值(如果有)就是190+(据我测试FF:192, IE9:195, Chrome:253, 不同环境结果可能有差异), 而element.style就是0

四、getComputedStyle与defaultView

如果我们查看jQuery源代码,会发现,其css()方法实现不是使用的window.getComputedStyle而是document.defaultView.getComputedStyle,唷?这是怎么一回事?
jQuery源码使用document.defaultView.getComputedStyle截图证明

实际上,使用defaultView基本上是没有必要的,getComputedStyle本身就存在window对象之中。根据DennisHall的说法,使用defaultView可能一是人们不太乐意在window上专门写个东西,二是让API在Java中也可用(这我不懂,忘指点~~)。

不过有个特殊情况,在FireFox3.6上不使用defaultView方法就搞不定的,就是访问框架(frame)的样式.

五、getComputedStyle兼容性

对于桌面设备:

  Chrome Firefox (Gecko) Internet Explorer Opera Safari
基本支持 支持 支持 9 支持 支持
伪类元素支持 支持 支持 不支持 不支持 支持

对于手机设备:

  Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
基本支持 支持 支持 WP7 Mango 支持 支持
伪元素支持 ? ? 不支持 ? ?

上面打问号的表示没有测试,是否兼容不知。如果您方便测试,欢迎将测试结果告知,这里将及时更新,并附上您的姓名,以谢您做的贡献。

我们先把注意力放在桌面设备上,可以看到,getComputedStyle方法IE6~8是不支持的,得,背了半天的媳妇,发现是孙悟空变的——郁闷了。不急,IE自有自己的一套东西。

六、getComputedStyle与currentStyle

currentStyle是IE浏览器自娱自乐的一个属性,其与element.style可以说是近亲,至少在使用形式上类似,element.currentStyle,差别在于element.currentStyle返回的是元素当前应用的最终CSS属性值(包括外链CSS文件,页面中嵌入的<style>属性等)。

因此,从作用上将,getComputedStyle方法与currentStyle属性走的很近,形式上则stylecurrentStyle走的近。不过,currentStyle属性貌似不支持伪类样式获取,这是与getComputedStyle方法的差异,也是jQuery css()方法无法体现的一点。

//zxx: 如果你只知jQuery css()方法,你是不会知道伪类样式也是可以获取的,虽然部分浏览器不支持。

例如,我们要获取一个元素的高度,可以类似下面的代码:

alert((element.currentStyle? element.currentStyle : window.getComputedStyle(element, null)).height);

您可以狠狠地点击这里:使用getComputedStyle和currentStyle 获取元素高度demo

结果FireFox下显示24px(经过计算了), 而IE浏览器下则是CSS中的2em属性值:
Firefox下显示的计算后的24px值 张鑫旭-鑫空间-鑫生活 IE9下显示的CSS中的2em值 张鑫旭-鑫空间-鑫生活

getComputedStyle方法与currentStyle属性其他具体差异还有很多,我以一个普通按钮做元素,遍历了其中靠谱的属性名和属性值,您可以狠狠地点击这里:getComputedStyle和currentStyle属性展示demo

仔细对比查看,我们可以看到不少差异,例如浮动属性,FireFox浏览器下是这个(cssFloat):
FireFox下的浮动属性名

IE7浏览器下则是styleFloat
IE7浏览器下的styleFloat属性 张鑫旭-鑫空间-鑫生活

而IE9浏览器下则是cssFloatstyleFloat都有。

等其他N多差异。

七、getPropertyValue方法

getPropertyValue方法可以获取CSS样式申明对象上的属性值(直接属性名称),例如:

window.getComputedStyle(element, null).getPropertyValue("float");

如果我们不使用getPropertyValue方法,直接使用键值访问,其实也是可以的。但是,比如这里的的float,如果使用键值访问,则不能直接使用getComputedStyle(element, null).float,而应该是cssFloatstyleFloat,自然需要浏览器判断了,比较折腾!

使用getPropertyValue方法不必可以驼峰书写形式(不支持驼峰写法),例如:style.getPropertyValue("border-top-left-radius");

更新于2018-05-30

getPropertyValue方法可以用来获取CSS原生变量值,如下示意:

const sidebarElement = document.querySelector('.sidebar');

// cssStyles包含sidebarElement元素的样式
const cssStyles = getComputedStyle(sidebarElement);

// 获取 --left-pos CSS 变量值
const cssVal = String(cssStyles.getPropertyValue('--left-pos')).trim(); 

// 输出cssVal
// 输出变量值是:100px 
console.log(cssVal);

设置CSS变量可以使用setProperty()方法,例如:

sidebarElement.style.setProperty('--left-pos', '200px');

兼容性
getPropertyValue方法IE9+以及其他现代浏览器都支持,见下表:

  Chrome Firefox (Gecko) Internet Explorer Opera Safari
基本支持 支持 支持 9 支持 支持

OK,一涉及到兼容性问题(IE6-8肿么办),感觉头开始微微作痛了~~,不急,IE自由一套自己的套路,就是getAttribute方法。

八、getPropertyValue和getAttribute

在老的IE浏览器(包括最新的),getAttribute方法提供了与getPropertyValue方法类似的功能,可以访问CSS样式对象的属性。用法与getPropertyValue类似:

style.getAttribute("float");

注意到没,使用getAttribute方法也不需要cssFloatstyleFloat的怪异写法与兼容性处理。不过,还是有一点差异的,就是属性名需要驼峰写法,如下:

style.getAttribute("backgroundColor");

如果不考虑IE6浏览器,貌似也是可以这么写:

style.getAttribute("background-color");

实例才是王道,您可以狠狠地点击这里:getPropertyValue和getAttribute获取背景色demo

结果FireFox下一如既往的rgb颜色返回(Chrome也是返回rgb颜色):
FireFox浏览器下一如既往的RGB颜色返回 张鑫旭-鑫空间-鑫生活

对于IE9浏览器,虽然应用的是currentStyle, 但是从结果上来讲,currentStyle返回的对象是完全支持getPropertyValue方法的。

九、getPropertyValue和getPropertyCSSValue

从长相上看getPropertyCSSValuegetPropertyValue是近亲,但实际上,getPropertyCSSValue要顽劣的多。

getPropertyCSSValue方法返回一个CSS最初值(CSSPrimitiveValue)对象(width, height, left, …)或CSS值列表(CSSValueList)对象(backgroundColor, fontSize, …),这取决于style属性值的类型。在某些特别的style属性下,其返回的是自定义对象。该自定义对象继承于CSSValue对象(就是上面所说的getComputedStyle以及currentStyle返回对象)。

getPropertyCSSValue方法兼容性不好,IE9浏览器不支持,Opera浏览器也不支持(实际支持,只是老是抛出异常)。而且,虽然FireFox中,style对象支持getPropertyCSSValue方法,但总是返回null. 因此,目前来讲,getPropertyCSSValue方法可以先不闻不问。

十、补充~结语

有了jQuery等优秀库,我们有熟悉底层的getComputedStyle方法的必要吗?

实际上,本文一直没有深入展开getComputedStyle方法一个很重要的,类似css()方法没有的功能——获取伪类元素样式。但从这一点上将,熟悉getComputedStyle方法有必要。

下一篇文章,我就将介绍如何实现getComputedStyle方法在伪类元素上的特异功能,实现CSS3 media queries下一些JS交互,及实际应用。

well, 开篇已经啰哩吧嗦不少内容了,这里就不再讲废话了。行文匆忙,文中难免有表述不准确之处,欢迎指正。欢迎补充,感谢阅读,希望本文的内容能够对您的学习有所帮助。

(本篇完)

分享到:


发表评论(目前97 条评论)

  1. 猪猪猪惠婷说道:

    我在其他地方看到用getComputedStyle获取元素属性,是这样写的:getComputedStyle(obj,false)[attr]为什么是false呢,上面不是说null吗

  2. 冯维祥说道:

    写的很到位,张老师不愧是我们前端学习榜样

  3. 陈子云说道:

    这个好,我的jqfree又充实了一点,css函数可以加上这个作为获取其css属性的操作

  4. 上头、说道:

    大大,刚刚看完文章每个例子都敲了(强迫症),获益良多!
    在微博上也有关注你! 我是justDooooooooIt(怒刷一波存在感)
    哈哈,我相信在未来的日子里会不断挖你的贴!支持!

  5. zhoucumt说道:

    打卡

  6. 你好说道:

    大神,在下想跟你交个朋友,有时间吗?不请客

  7. heeerin说道:

    话说getComputedStyle只读不能设置,那咋办

  8. a豹说道:

    经过测试:style.getAttribute(“float”)不能获取float。 要通过style.styleFloat或 style.getAttribute(“styleFloat”)才能获取。

    • 小小程序员说道:

      在ie中用.currentStyle.getAttribute(“float”)获取不到值,而‘border-top-left-radius’直接可以获取到,而转成驼峰“borderTopLeftRadius”获取不了,感觉在ie里还是存在一些bug啊

  9. 不二说道:

    最喜欢你的探究精神了!知其然还要知其所以然这种态度很棒!!没事就爱看你的文章!

  10. element.style方法说道:

    element.style方法读取属性值的有限制,只能读取内联样式属性,而且谁会写一大堆内联样式呢,基本都是用外部css样式,这个方法根本读不出来,所以此方法很鸡肋啊

  11. 小叶子说道:

    谢谢大神啊,受益匪浅,半年前想自己写一个动画特效,结果用 js 发现怎么也获取不了left值,最后恼羞成怒不想写了,如今又想重新写一遍动画,看到了这篇文章,顺利的完成,谢谢啊!

  12. 七里香说道:

    学到了很多 ,谢谢

  13. 麻雀说道:

    能不能出些计算滑动惯性的教程来,就是我们平常滑动手机的时候会有惯性带动慢慢停下来。就像iscroll这个插件一样,我们都知道用这个插件,但是我想实现一些其他的功能必须利用惯性滑动但是又不能用iscroll来做的事情,这里我就想研究下惯性滑动的原理和实现,但是我物理学的不好,不知道怎么计算。希望大牛出个教程和简单实现例子。谢谢。

  14. CoolHector说道:

    虽然这是一篇旧文了,给后面同学作下参考吧。
    六、getComputedStyle与currentStyle
    例如,我们要获取一个元素的高度,可以类似下面的代码:
    alert((element.currentStyle? element.currentStyle : window.getComputedStyle(element, null)).height);

    以及demo里面的源代码有误,大神木有写element.currentStyle的具体的css样式属性,比如该例的height属性。应为:element.currentStyle.height

  15. 小郭说道:

    怒赞

  16. bigtall说道:

    思路很清晰,讲的很好。

  17. 吴默说道:

    window.getComputedStyle(aa,null).getPropertyValue(“style”)和window.getComputedStyle(aa,null).style有什么区别呀

  18. PageYe说道:

    您好,您的这句话【getComputedStyle语法】var style = window.getComputedStyle(“元素”, “伪类”);这句话中建议把“元素”的引号去掉,因为这样写参数很容易引起误解,实际上这个元素是个dom对象,不应该传字符串

    经亲自检测,发现,window.getComputedStyle(dom,””)只能取到伪元素,比如:::after,::before,::first-letter,::first-line但是对于伪类,如::hover:active:focus:active是取不到的

    • lixinjie说道:

      对,我也碰到了这样的问题。当我在元素上加上引号后,浏览器就报错了,大意是参数一不是元素类型,然后看到了这篇文章,回去仔细理解那句话发现这个错误。测试了 “:after” 和 “:hover” 前者能获取到,后者不行。这句话应该这样说:“对于元素的伪元素能获取到,而元素的伪类则不行”。

  19. 赵明亮说道:

    在学习的道路上经常上楼主的博客,学习经验了

  20. 武穴论坛说道:

    太好了,感谢!就是找这个的具体用法,找来一圈,终于找到你这里看到答案。感恩!

    getcurrentstyle

  21. DHH说道:

    我想请教下,text-overflow: ellipsis 这个样式,在文字长度过长的时候才会应用,这个有无办法知道ellipsis有没有应用到页面上?

  22. hoyin说道:

    涨姿势了

  23. 我是普通青年说道:

    好吧,我是普通青年一枚,尽管我已经看了几次这篇文章,但是就是懒得动手。

  24. 独醉说道:

    谷歌浏览器报错:Uncaught TypeError: Failed to execute ‘getComputedStyle’ on ‘Window’: parameter 1 is not of type ‘Element’.
    这是为什么?

    • 李斯说道:

      传入的 element 为空了

    • 小糖说道:

      我第一次写是把getComputedStyle(ele,null)里的逗号写成点号了,也是这样报错的

    • 颜仔说道:

      我也被提示过这个问题,不过是混合了js和jq的写法,改为js的写法就没有问题了;比如我是用jq写法设置变量

      • LLL说道:

        var margin_sub_obj = options.document.getElementsByClassName(“secondmenu1”);
        console.log(margin_sub_obj);
        var margin_sub = “0px”;
        var margin_sub_w = “0px”;
        if(margin_sub_obj.currentStyle){
        margin_sub = margin_sub_obj.currentStyle[“height”];
        margin_sub_w = margin_sub_obj.currentStyle[“width”];
        }else{
        margin_sub = window.getComputedStyle(margin_sub_obj, null)[“height”];
        margin_sub_w = window.getComputedStyle(margin_sub_obj, null)[“width”];
        }
        我也报这个错,没找到原因啊

    • zzy说道:

      第一个参数不是元素

  25. Zion说道:

    很喜欢鑫哥的文章,也很喜欢看你钓鱼的文章,哈哈~

  26. 大雄来了说道:

    好文章!

  27. 奔波儿灞说道:

    getComputedStyle第二个参数,只能获取伪元素的样式,而不是伪类。

  28. nono说道:

    看了第一段就来评论了,你懂的

    removeProperty和setPropertyValue是用在哪里的。

  29. wanggang说道:

    二是让API在Java中也可用(这我不懂,忘指点~~)

    第三次读此文章了,这次读来相对理解的更轻松了。而且看到了这句,我想获取没必要再提,只是留给后来者看下吧

    hybrid开发中,android中的webview加载页面,android可以调用webview页面中的js方法,必须将js方法写在window下

  30. yuanoook说道:

    为了精确存取样式,
    我第一次是这么做的
    return this.style[arguments[0]];
    我第二次是这么做的
    return getComputedStyle(this)[arguments[0]];
    我第三次是这么做的
    return this.style[arguments[0]] || getComputedStyle(this)[arguments[0]];

    三次取值有时候不一样,第三次才是我想要的。
    因为第二次的值不一定等于行内样式的值,如果行内样式的值超级大 比如 11110000000px 结果 第二次取的值会小一些。

  31. getAttribute疑问?说道:

    也不知道你能不能看到,但是你这个里边的getAttribute跟DOM中的getAttribute应该不是同一个吧?这个是属于什么范畴的?抱歉问这么蠢的问题,但是,我刚开始学习javascript,周围也没同学商量……Sorry了……

  32. chenxiaoniu说道:

    你的那个getComputedStyle(elem,null).height在Firefox中高度显示为2em,的浏览器版本是多少?我在最新上测试的是24px……

  33. alex020说道:

    目前最新的jquery版本css()也是不支持伪类的选择么?

  34. zfnotes说道:

    的确好文章!以下内容仅供参考!
    DennisHall所说“使用defaultView是让API在Java中也可用”,可能是在说:
    如果在.html页面中插入Applet时,可以通过原Natscape的JS2J软件包,现jre\lib\plugin.jar标准包内的package:netscape.javascript.*中的JSObject.getWindow(this); 方法,在applet逻辑中,获取.html之window对象!
    由于getComputedStyle()方法属于“非标”,故DennisHall可能认为,将其封装在defaultView中,更为合适吧?
    你可能会问:为什么要插入(现为)到html?
    答案应该是:签名Applet+JNI(Java Native Interface)将有能量触发Local-Disk上的.exe/.dll…

  35. lee说道:

    function getStyle(elem, cssArr){
    if(elem.style[cssArr]) return elem.style[cssArr];
    // for IE
    else if(elem.currentStyle) return elem.currentStyle[cssArr];
    // for ff
    else if(window.getComputedStyle){
    cssArr = cssArr.replace(/([A-Z])/g, ‘-$1’).toLowerCase();
    return window.getComputedStyle.getPropertyValue(cssArr);
    }
    }
    return null;
    }

    在FF下测试:
    getStyle(ele,’borderWidth’),发现返回空,而在IE、chrome中均可正常显示
    问题:在FF下如何得到例如borderWidth、borderColor的值

  36. Jeanys说道:

    好文章。。就是配图实在伤不起。。尤其是收藏到无觅。。。。。之前还看过您一篇清除浮动的文章。。里面那白细胞的插图看的我给哆嗦的。。。

  37. xiaozhu说道:

    楼主先膜拜一下
    if (oStyle.getPropertyValue) {
    alert(“getPropertyValue下背景色:” + oStyle.getPropertyValue(“background-color”));
    } else {
    alert(“getAttribute下背景色:” + oStyle.getAttribute(“backgroundColor”));
    }
    这里如果换成
    if (oStyle.getAttribute) {
    alert(“getAttribute下背景色:” + oStyle.getAttribute(“backgroundColor”));
    } else {
    alert(“getPropertyValue下背景色:” + oStyle.getPropertyValue(“background-color”));
    }
    先判断IE的话,就可以不用考虑这一句了,“对于IE9浏览器,虽然应用的是currentStyle, 但是从结果上来讲,currentStyle返回的对象是完全支持getPropertyValue方法的。”对么?
    之前我写js的时候从没有用过getPropertyValue和getAttribute,看来以后必须要加上了,也算是一种习惯。

  38. null说道:

    window.getComputedStyle 的第二个参数应该是“伪元素”而不是“伪类”
    document.defaultView 返回的就是 window 对象

  39. 田田说道:

    好吧。我知道我一开始为什么获取不了了。是因没有写window

  40. 田田说道:

    因此对于一个光秃秃的元素,getComputedStyle方法返回对象中length属性值(如果有)就是190+(据我测试FF:192, IE9:195, Chrome:253, 不同环境结果可能有差异), 而element.style就是0。对一句话产生了及大的兴趣!可是不知道怎么测试。

  41. 小蘑菇说道:

    今天在看touchslider.com里面用到了window.getComputedStyle(scroller[0]).webkitTransform;莫非自从css3开始就有很多WebKitCSSMatrix这些类型的不常见的函数吗,求文档~

  42. WEB湛说道:

    在对于display属性值的获取上也有一些问题,某div元素我设置了如下样式
    div{
    float:left;
    display:inline;
    }
    这是消除IE6下双倍边距的常用方式
    当使用currentStyle获取display属性的时候会得到inline的正确结果
    然而使用chrome或者FF得到的却是block
    这个差异怎么解决呢?

    • 张 鑫旭说道:

      @WEB湛 其实chrome或者FF才是正确的结果。浮动、绝对定位会让元素block化。如果想要得到inline,可以先style.cssFloat = “none”; 再获取,然后设置style.cssFloat = “left”。 话说没有margin值就没有双倍边距的问题;再者,有margin值可以改为外部padding值控制。

  43. kis龘说道:

    我想知道在win7下有ie6 的绿色版吗? 使用兼容模式下的 quirks 模式不是ie6 ,

  44. wade04035016说道:

    了解的越多,就越发现,我们这些苦逼的人被浏览器厂商玩死了

  45. 过往云烟说道:

    不错 写的很好 我用IE9 测试 发现 很多原本IE 并不兼容的东西 IE9 很多都兼容了 看来以后 javascript的路会好走点

  46. 紫檀说道:

    必须好…

  47. 小杜说道:

    zxx大神,第六大点的这句错了
    alert((element.currentStyle? element.currentStyle : window.getComputedStyle(element, null)).height);

    element.currentStyle[‘height’]

  48. xiaofanV587说道:

    ZXX的文章每日必看

  49. 三桂说道:

    zxx对于问题的探究精神值得大家学习啊…