译自:http://css-tricks.com/efficiently-rendering-css/
无可否认我并不经常考虑这个问题… 我们书写的CSS的效率如何,浏览器渲染它的速度如何?
浏览器的开发者肯定关心这个问题(页面加载越快,人们用着越开心)。Mozilla有篇文章 about best practices。Google同样致力于让web更快,他们也有篇文章article about it。
先来了解一下他们提出的主要想法,然后讨论其实用性。
弄明白浏览器是怎样解读CSS选择器的重要一件事情是:浏览器按“从右向左”读取。意味着在选择器 ul > li a[title="home"] 中,首先被解析的是a[title="home"]。这第一部分也被称为“目标选择器”,最终选择的元素是它。
这里有四种目标选择器:ID,class,tag和通配符。按照效率排列如下。
#main-navigation { } /* ID (最快) */
body.home #page-wrap { } /* ID */
.main-navigation { } /* Class */
ul li a.current { } /* Class *
ul { } /* Tag */
ul li a { } /* Tag */
* { } /* 通配 (最慢) */
#content [title='home'] /* 通配 */
结合“从右至左”和目标选择器的思想,可以看出这样的选择器效率不是很高:
#main-nav > li { } /* 比你想象的要慢 */
即使这让人感到有悖常理…因为ID最有效,所以我们认为浏览器会快速地找到ID,然后很快地找到li子元素。但实际上,最先运行的是相对低效的li元素选择器。
千万别这样做:
ul#main-navigation { }
ID是唯一的,所以它们不需要和标签在一起。这样做反而会降低效率。如果可以避免的话,也不要用class修饰。class不唯一,所以理论上你可以对多个不同的元素应用一个class。如果想让标签控制样式,你可能会加以标签修饰(eg:li.first),但这种做法很罕见,所以还是别这样做。
David Hyatt:
后代选择器在CSS中是最昂贵的选择器。贵得要命——尤其是把它和标签或通配符放在一起!
换言之,像下面这样的选择器简直是效率的灾难:
html body ul li a { }
我不确定这能让我们学到很多,因为如果在你的CSS中有大量的选择器未曾匹配任何东西…这太古怪了。不过也挺有趣,“从右至左”的解释一个选择器,一旦匹配失败就停下来,相比继续解释下来所用精力更少。
看看这个:
#main-navigation li a { font-family: Georgia, Serif; }
字体样式,你可能不需要特意从一个选择器(a标签)开始(如果你只想换个字体)。这样可能达到同样的效果,但更加高效:
#main-navigation { font-family: Georgia, Serif; }
来自David Hyatt的噩耗:
关于CSS3选择器的可悲的事实是,如果你关心页面性能的话,他们真不该被使用!
整个评论是值得一读的。
CSS3选择器(例如:第n个孩子)是令人难以置信的好,在帮助我们锁定我们想要的元素的同时保持标记的干净和语义化,但事实是,这些花哨的选择器让更多的浏览器资源被密集使用。
到底怎么回事,我不应该使用它们吗?让我们想点实用性吧!
开头提到Mozilla的文章?已经有10年了。事实上,10年前的计算机更慢。这些东西在那时候更重要。10年前我刚要21岁,根本不知道CSS是什么,所以没法带你去那些古老的学校…但我感觉,我们之所以不关心渲染效率的问题,是因为它从来都不是个大问题。
这是我的想法:上面提到的最佳实践都是有意义的。你可以遵循,它们不会限制你的CSS能力。但你也不必太教条。如果你刚好需要改进从前的网站,又刚好没有考虑过这些想法,不妨看看你的样式表,哪里可以做得更好。如果你的网站没有渲染速度的问题,不用去担心,以后注意就可以了。
现在我们知道ID是最高效地选择器。如果你想使页面渲染最高效,你可以给每一个元素加上唯一的ID,然后对每个ID选择器应用样式。这超级快,同样超级荒谬。这样的页面会极端的没有语义,并且很难维护。即使在以表现为主的网站,也不会这样做。我想,这堂课并不是为了高效的CSS而牺牲语义和可维护性。
感谢Jason Beaudoin email给我想法。如果有谁知道这个东西,或者你有额外的提示,请告诉我!
只是作为一个速记,我想提一提,因为CSS样式选择器也在许多JavaScript库中使用,这些相同的概念也同样适用。 ID选择将是最快的,而复杂的后代选择等会慢一些。