今天学习了CSS各种选择器,对其效率问题有些疑问,故总结了一些学习笔记php
有不少人都忘记了,或在简单的说没有意识到,CSS在咱们手中,既能很高效,也能够变得很低能。这很容易被忘记,尤为是当你意识到你会的太少,CSS代码效率很低的时候。css
下面的规则只真正被应用到那些速度要求很高,有成百上千的DOM元素被绘制在页面上的大型网站。可是,实践出真理,这和你是在建立下一个Facebook,仍是写一个本地的展现页面都没有关系,多知道一点老是好的。html
对咱们大多数人来讲,CSS选择器并不陌生。最基本的选择器是元素选择器(好比div),ID选择器(好比#header)还有类选择器(好比.tweet)。web
一些的不常见的选择器包括伪类选择器(:hover),不少复杂的CSS3和正则选择器,好比:first-child,class ^= “grid-”.浏览器
CSS选择器具备高效的继承性,引用Steve Souders的话, CSS选择器效率从高到低的排序以下:app
以上引用自Steve Souders的Even Faster网站、性能
咱们不得不提的是,纵使ID选择器很快、高效,可是它也仅仅如此。从Steve Souders的CSS Test咱们能够看出ID选择器和类选择器在速度上的差别很小很小。学习
在Windows系统上的Firefox 6上,我测得了一个简单类选择器的(reflow figure)重绘速度为10.9ms,而ID选择器为12.5ms,因此事实上ID比类选择器重绘要慢一点点。测试
ID选择器和类选择器在速度上的差别基本上没有关系。网站
在一个标签选择器(a)的测试上显示,它比类或ID选择器的速度慢了不少。在一个嵌套很深的后代选择器的测试上,显示数据为440左右!从这里咱们能够看出ID/类选择器 和 元素/后代选择器中间的差别较大,可是相互之间的差别较小。
注意: 这些数据可能在不一样计算机和浏览器中间的差别较大。强烈地建议你们在本身的机子上测试一下。
你能够有一个标准的选择器好比 #nav,来选择任何带有ID为”nav”的元素,或在你能够有一个组合选择器好比#nav a,来选择任何在ID为’nav’的元素里面的连接元素
此刻,咱们读这些是从左到右的方式。咱们是先找到#nav,而后从它的里面找其余元素。可是浏览器解析这些不是这样的:浏览器解析选择器是从右到左的方式。
在咱们看来,#nav里面带了一个a,浏览器倒是看到的a在#nav里面。这些细微的差别对选择器的效率有很大的影响,同时学这些差别也是颇有价值的。
若是想要知道更多浏览器这样解析的缘由,请看Stack Overflow上的讨论
浏览器从最右边的元素开始(它想要渲染的元素),而后用它的方式回溯DOM树比从DOM树的最高层开始选择向下寻找,甚至可能达不到最右边的选择器—关键的选择器要高效。
这些对CSS选择器的效率有很大的影响。
关键选择器,正如前面讨论的同样,是一个复杂的CSS选择器中最右边部分。它是浏览器最早寻找的。
如今咱们回到讨论开始的地方,哪类选择器是最高效的?哪一个是会影响选择器效率的关键选择器;写CSS代码的时候,关键选择器是可否高效的决定因素。 一个关键CSS选择器像这样:
1
|
#content .intro {..}
|
是否是高效选择器好比类选择器天生就高效?浏览器会寻找.intro的实例(可能会不少),而后沿着DOM树向上查找,肯定刚才找到的实例是否在一个带有ID为”content”的容器里面。
可是,下面的选择器就表现的不是那么好了:
1
|
#content * {..}
|
这个选择器所作的是选择全部在页面上的单个元素(是每一个单个的元素),而后去看看它们是否有一个 #content 的父元素。这是一个很是不高效选择器由于它的关键选择器执行开销太大了。
运用这些知识咱们就能够在分类和选择元素的时候作出更好的选择。
假设你有一个复杂的页面,它至关巨大而且在你的一个很大很大的站点上。在那个页面上有成百上千甚至上万的 a 标签。它还有一个小的社交连接区域放在一个ID为#social的Ul里面。咱们假设它们是Twitter,Facebook,Dribbble还有 Google+的连接吧。在这个页面上咱们有四个社交连接和成百上千的其余连接。 下面的这个选择器就天然的不是那么高效和合理了:
1
|
#social a {…}
|
这里发生的状况是浏览器会在定位到#social区域下的四个连接以前获得页面上全部成千上万的连接。咱们的关键选择器匹配了太多咱们不感兴趣的其余元素。
为了补救咱们能够给每一个在社交连接区域的 a 增长一个更特殊、明确的选择器 .social-link , 可是这好像有点违背咱们的认知:当咱们能用组合选择器的时候就不要放没必要要的类标示在元素上。
这就是为何我对选择器的性能如此感兴趣的缘由了:必须在web 标准最佳实践和速度之间的保持平衡。
一般咱们有:
1
2
3
4
5
6
|
<ul id=
"social"
>
<li><a href=
"#"
class=
"twitter"
>Twitter</a></li>
<li><a href=
"#"
class=
"facebook"
>Facebook</a></li>
<li><a href=
"#"
class=
"dribble"
>Dribbble</a></li>
<li><a href=
"#"
class=
"gplus"
>Google+</a></li>
</ul>
|
CSS:
1
|
#social a {}
|
咱们如今最好有:
1
2
3
4
5
6
|
<
ul
id
=
"social"
>
<
li
><
a
href
=
"#"
class
=
"social-link twitter"
>Twitter</
a
></
li
>
<
li
><
a
href
=
"#"
class
=
"social-link facebook"
>Facebook</
a
></
li
>
<
li
><
a
href
=
"#"
class
=
"social-link dribble"
>Dribbble</
a
></
li
>
<
li
><
a
href
=
"#"
class
=
"social-link gplus"
>Google+</
a
></
li
>
</
ul
>
|
加上CSS:
1
|
#social .social-link {}
|
这个新的关键选择器将会匹配更少的元素,这意味着浏览器可以很快的找到它们并渲染特定的样式,而后专一于下一件事。
另外,事实上咱们能够用.social-link{}更清晰的选择,而不是过度限制它。阅读下一部分你会缘由…
简单的重述一次,你的关键选择器会决定浏览器的工做量,所以,咱们应该重视一下关键选择器
如今咱们知道了什么是关键选择器,还有它是大部分工做的来源,可是咱们能够更乐观一点。拥有一个明确的关键选择器最大的好处就是你能够避免使用过分限制选择器。一个过分限制选择器可能像:
1
|
html body .wrapper #content a {}
|
这里的写的太多了,至少3个选择器是彻底不须要的。它能够最多像这个样子:
1
|
#content a {}
|
这会发生什么呢? 首先第一个意味着浏览器不得不寻找全部的 a 元素,而后检查他们是否在一个ID为”content”的元素中,而后如此循环直到HTML标签。这样形成了太多的咱们不太想要的花费。了解了这个,咱们获得一些更现实的例子:
1
|
#nav li a{}
|
变成这个:
1
|
#nav a {}
|
咱们知道若是a在li里面,它也一定在#nav里面,全部咱们能够立刻把li从选择器组中拿掉。而后,既然咱们知道在页面中只有一个ID为nav的元素,那么它依附的元素就是彻底没有关系得了,咱们也能够拿掉ul
过分限制选择器使浏览器工做比它实际须要的更繁重,花费的时间更多。咱们能够删掉没必要需的限制,来使咱们的选择器更简单和高效。
最短的答案是:或许不是。
最长的答案是:它取决于你正在搭建的站点。若是你正在为你的晋升而努力,那么就好好写出简单、高效的CSS代码吧,由于你可能不会感受到它给你带来的改变。 若是你正在搭建下一个每一个页面都以毫秒计算的Amazon网站,这样有时速度会很快,但有时可能不是。
浏览器将会在解析CSS的速度上变得更好,甚至在手机端。在一个网站上,你不太可能会觉察到一个低效的CSS选择器,可是….
它确实发生了,浏览器仍是不得不去作咱们讨论的全部工做,不管它们变得多快。即便你不须要或者甚至不想实践任何一个,可是它都是咱们值得学习的知识。请记住选择器可能会让你付出很大代价,你应该避免盯着一个看。这意味着若是你发现你本身在写像这样的:
1
|
div:nth-of-type(
3
) ul:last-child li:nth-of-type(odd) *{
font-weight
:
bold
}
|
这时,你可能就作错了。
如今,在高效选择器的世界我仍是一个新人。因此若是我忘记了什么,或者你有须要补充的,请在评论里面留言。
我还不能彻底介绍Steve Souders的网站和书籍(《更快速网站》、《高性能网站》),它们是如此之好,以致于值得你花更多时间来阅读和推荐。这个家伙只有他本身才了解本身!
英文原文:Writing efficient CSS selectors,编译:@freestyle21 和@沈涛-WEB工程师