网站CSS选择器性能讨论

    CSS选择符由一些初始化参数组成,这些参数指明了要应用这个CSS规则的页面元素。作为一个网站的前端开发工程师,应该避免编写一些常见的开销很大的CSS选择符模式,尽量编写高效的CSS选择符,从而加快页面的渲染速度,缩短页面呈现时间。

我们先来看一下safari和webkit的架构师David Hyatt的两段话:

  1. 样式系统从最右边的选择符开始向左进行匹配规则。只要当前选择符的左边还有其他选择符,样式系统就会继续向左移动,直到找到和规则匹配的元素,或者因为不匹配而退出
  2. 如果你非常在意页面的性能那千万别使用CSS3选择器。实际上,在所有浏览器中,用 class 和 id 来渲染,比那些使用同胞,后代选择器,子选择器(sibling, descendant and child selectors)对页面性能的改善更值得关注。

Google 资深web开发工程师Steve Souders对CSS选择器的效率从高到低做了一个排序:

1.id选择器(#myid)2.类选择器(.myclassname)3.标签选择器(div,h1,p)4.相邻选择器(h1+p)5.子选择器(ul < li)6.后代选择器(li a)7.通配符选择器(*)8.属性选择器(a[rel=”external”])9.伪类选择器(a:hover,li:nth-child)

上面九种选择器中ID选择器的效率是最高,而伪类选择器的效率则是最底。详细的介绍大家还可以点击Writing efficient CSS selectors

综合上面的顺序,我们清楚的知道,id和类名用于关键选择器上效率是最高的,而CSS3的仿伪类和属性选择器,虽然使用方便,但其效率却是最低的

知道了基本原理以后,我们编写CSS时就应该注意了。下面举几个例子,让大家理解的更透彻一些:

1.不要在编写id规则时用标签名或类名

  1. BAD
  2. button#backButton {…}
  3. BAD
  4. .menu-left#newMenuIcon {…}
  5. GOOD
  6. #backButton {…}
  7. GOOD
  8. #newMenuIcon {…}

由于样式系统从最右边的选择符开始向左进行匹配,只要当前选择符的左边还有其他选择符,样式系统就会继续向左移动,直到找到和规则匹配的元素,或者因为不匹配而退出,所以,在button#backButton {…}中,样式系统先找到id为backButton的元素,然后继续向左匹配,查看该元素的标签名是不是button,如果不是,查找下一个id为backButton的元素,再检查这个元素的标签名,如此周而复始,直到到达文档末尾。如果只是#backButton {…},则样式系统找到id为backButton的元素后,因为左边没有其他选择符了,它就退出而结束查找了。

另外,根据HTML规范,id在HTML中是唯一的,也就是说一个HTML页面只限定有一个id为“XX”的元素,而不限制拥有这个ID元素的标签名,所以,在button#backButton {…}中,button标签完全是无意义的,可以,而且应该去掉,button#backButton {…}与#backButton {…}是等价的。在#backButton前多写了button,只会引起样式系统向左移动,继续查找页面元素,损耗页面性能,延长页面渲染时间。

另一方面,在id元素前面添加标签名,还会引起另一个致命的问题,比如原来id为backButton的标签名是button,如果原来样式声明写成button#backButton {…},则现在需要把button标签改成input,id不变,则button#backButton {…}声明的样式规则在这个id同样为backButton的input元素上不起作用,不信大家可以自己动手编写试一下。

2.不要在编写class规则时用标签名

  1. BAD
  2. treecell.indented {…}
  3. GOOD
  4. .treecell-indented {…} //语言化和标签名绑在一起 假设treecell
  5. BEST
  6. .hierarchy-deep {…} //语言化和标签名无关

原理参考第一条。

3.把多层标签选择规则用class规则替换,减少css查找

  1. BAD
  2. treeitem[mailfolder=”true”] > treerow > treecell {…}
  3. GOOD
  4. .treecell-mailfolder {…}

4.避免使用子选择器

现在我们来看看David Hyatt的第3段话:后代选择器在CSS中是最昂贵的选择器。贵得要命——尤其是把它和标签或通配符放在一起!

  1. BAD
  2. treehead treerow treecell {…}
  3. BETTER, BUT STILL BAD (see next guideline)
  4. treehead > treerow > treecell {…}

标签后面最好永远不要再增加子选择器

  1. BAD
  2. treehead > treerow > treecell {…}
  3. GOOD
  4. .treecell-header {…}
  5. BAD
  6. treeitem[IsImapServer=”true”] > treerow > .tree-folderpane-icon {…}
  7. GOOD
  8. .tree-folderpane-icon[IsImapServer=”true”] {…

5.依靠继承

  1. BAD
  2. #bookmarkMenuItem > .menu-left { list-style-image: url(blah) }
  3. GOOD
  4. #bookmarkMenuItem { list-style-image: url(blah) }

最后,我们来做个总结,网站编写CSS时,应该优先考虑使用class选择器,避免使用通配符选择器(*)和属性选择器(a[rel=”external”]),后代选择器与标签选择器结合使用也应避免。使用id选择器的性能最好,但是编写时要注意其唯一性,谨慎使用。CSS3选择器(例如::nth-child(n)第n个孩子)在帮助我们锁定我们想要的元素的同时保持标记的干净和语义化,但事实是,这些花哨的选择器让更多的浏览器资源被密集使用。引用David Hyatt关于CSS3选择器的论述:如果你关心页面性能的话,他们真不该被使用!

  1. 英文文档参考资源:
  2. http://blog.archive.jpsykes.com/151/testing-css-performance/
  3. http://blog.archive.jpsykes.com/152/testing-css-performance-pt-2/
  4. http://blog.archive.jpsykes.com/153/more-css-performance-testing-pt-3/
  5. Testing CSS Performance  Jon Sykes
  6. https://developer.mozilla.org/en-US/docs/CSS/Writing_Efficient_CSS?redirectlocale=en-US&redirectslug=Writing_Efficient_CSS
  7. •Original Document Information
  8. •Author: David Hyatt
  9. •Original Document Date: 2000-04-21
  10. •Original Document URL: http://www.mozilla.org/xpfe/goodcss.html
  11. http://css-tricks.com/efficiently-rendering-css/
  12. (Efficiently Rendering CSS)
  13. https://developers.google.com/speed/docs/best-practices/rendering?hl=zh-CN
  14. (google建议)

28 responses

Leave a Reply

Your email address will not be published. Required fields are marked *

  1. […] 网站CSS选择器性能讨论 This entry was posted in All on 24/01/2013 by tong. […]

  2. 教程文 看看 谢谢

  3. W3school_xiaomin says:

    那都以这么写的话如何重用,可用性大大降低。

  4. 招商引资网 says:

    非常喜欢您的文章,每次都写的那么深刻,有哲理,有思想。这样的文章值得我们学习。

  5. 120628826 says:

    很不错啊 新手学习中……

  6. Nananedo says:

    选择器的性能差异只有在极差的html的结构、极多的标签时会体现出来;
    而且好的选择器可以让我们更方便的实现特定的效果,甚至是动画效果;
    在硬件飞速发展的今天,我倾向于使用更好的选择器,而不是复杂的实现结构。

  7. zihan says:

    后代选择器性能真如此不堪?那网站的多级菜单如何是好?
    例如ul li a,难道为此为每一个li和a都加入class? 这样的代价与选择器性能上,做何取舍或是有更好的方法?

  8. 635997946 says:

    样式系统先找到id为backButton的元素,然后继续向左匹配,查看该元素的标签名是不是button,如果不是,查找下一个id为backButton的元素,再检查这个元素的标签名,如此周而复始,直到到达文档末尾?id选择器是唯一,那也就是页样式中理论上不会存在两个同名的id为#backButton的选择器,那我是不是可以理解成样式系统只会寻找到一次

  9. Tiegen Zhutg says:

    不能这样理解,div#tip和#tip中,如果id为tip的元素的标签为span,div#tip这个选择器声明的规则是不会对这个span元素起作用的。所以,尽管id唯一,但只有#左边还有样式选择器,CSS查找匹配仍会继续。

  10. Tiegen Zhutg says:

    其实编写良好的css代码而言,虽然每个li和a都加了class,但是编写后的总文件反而比ul li a 这样编写的选择器要小,原因很简单,原来的ul li a现在改写成了.list-item,语义结构清晰,不容易跟页面其他元素起冲突,原来的ul li a为了避免被别的优先级高的样式覆盖,势必要增加id或class前缀,比如写成#list li a 这样总体反而很长,而且CSS性能也不是很好。如果你尝试用class重新css文件,而且尽量只写一层class,少用子选择器,你会发现CSS总体文件反而比以前要小很多。当然,可能html文件因为增加了不少class属性会变大,但现在标准网站都采用了gizp压缩,一般比较好的gizp压缩后,只有原来的1/8大小,有些压缩等级大的能到原来的1/10以上。所以,在html中增加class属性没什么太大关系,又能改善CSS渲染性能,缩小CSS总文件大小,而且通过修改class来修改页面,扩展通用性也不错,何乐不为呢?你只有自己去尝试了,就会慢慢发现它的好处的。

  11. Tiegen Zhutg says:

    所谓极差的html结构,其实就是页面元素节点非常多,元素嵌套又比较深的结构。但是在一个大型的网站中,比如阿里巴巴,淘宝这样的网站,由于业务功能的复杂性,页面结构相应也变得非常复杂,元素嵌套层级很多,这种情况下编写良好的CSS代码,就能相应增加页面渲染速度了。

  12. […] 原文链接:网站CSS选择器性能讨论 if (typeof DUOSHUO !== 'undefined') DUOSHUO.EmbedThread('.ds-thread');  […]

  13. Michael Shen says:

    有时候可能需要在维护开发和性能中不停的权衡

  14. 蓝海宏图营销策划 says:

    是不是这样做就可以的啦

  15. Braden Han says:

    很好的文章,收益匪浅。。。

  16. egirlasm says:

    1.高速发展的硬件跟宽带。
    2.存在即是合理,只要不滥用,那即是有用的。
    每个 li 标签 加 class ? 我只能说是脑残行为。
    我不觉得 阿里巴巴,淘宝那样的大网站因为多写了几十行选择器而拖垮速度,
    因为每个li 加的class 导致html 多了几个kb 造成的 访问速度变慢,臃肿,只能说是操蛋的傻逼写的。

  17. […] 网站CSS选择器性能讨论 « 阿里巴巴(中国站)用户体验设计部博客. […]

  18. […] 文章转自:网站CSS选择器性能讨论 […]

  19. gamgam says:

    写得很好啊,原理理解了,才更方便做事,磨刀不误砍柴功嘛,赞一个。不过实际使用的时候,看取舍咯,后代选择器使用率还是很高的(我不会告诉你我是懒得命名~)。

  20. […] 网站CSS选择器性能讨论 « 阿里巴巴(中国站)用户体验设计部博客. […]

  21. […] 原文链接:网站CSS选择器性能讨论 […]

  22. 烛前 says:

    我觉得还是要看页面复杂度和目标人群(浏览器)等等综合决定的,如果页面结构清晰简洁而有针对更加现代的浏览器,CSS3 selector, why not?

  23. Mayon says:

    我的想法是,这些东西需要了解和理解。如果遇到对性能要求高的站点,可以迅速用上,至于其它时候,该怎么写就怎么写。

  24. Amrio says:

    既然都说了GZIP了,那么在CSS文件上面GZIP效率不更高?HTML非静态能开缓存?就算能开缓存,那也不是常态吧?常态是CSS文件变动较少,而HTML变动较多

  25. […]                                                                  网站CSS选择器性能讨论                                                                  […]

  26. An outstanding share! I’ve just forwarded this onto a coworker who was doing a little research on this.
    And he actually ordered me lunch simply because I stumbled upon it for him…
    lol. So allow me to reword this…. Thank YOU for the meal!!
    But yeah, thanks for spending the time to discuss this issue here on your web page.

  27. Besides many other capabilities it offers, Firefox allows a person to phone
    a make contact with without returning to the telephone feature.