搞效率的CSS选择器(Selector)不是一个新的主题,对于网页设计师而言,知道如何撰写CSS,是一个基本的技术能力,而了解如何撰写高效率的CSS则能让网页设计师的CSS作品获得更好的品质。
注意:这里所指的不是让开发者很有效率的写CSS,而是让开发者写出来的CSS Selector能很有效率的被浏览器执行。
本篇描述的规则,比较适用于非常需要全面提升「速度」的网站,像是每个页面的DOM元素都超过1000个以上的网站。如果是像我这种小小的博客,提升的效率就完全不明显,但身为专业的网页设计师,你还是必须把这些规则放在心上。
CSS 选择器(Selectors)
CSS 选择器你应该不陌生,我们可以透过基本的选择器去指定要处理的DOM元素,像是指定标签(div,span,body…)、ID(#header)、Class(.post)等选择器。
还有一些较不常见的伪类(pseudo-classes),如 :hover,或更为复杂的CSS3及regex选择器,如 :first-child或 [class^=”grid-“] 表示挑出所有类别名称以grid-为开头的元素。
而根据网站效率专家 Steve Souders 指出,各种CSS选择器的效率由高至低排序如下:
1. ID (#id)
2. Class (.class)
3. Type (即HTML标签,如div)
4. 邻接选择器 (如: h2+p,仅作用于邻接h2的p元素)
5. Child (如: li>ul)
6. Descendant (如:ul a)
7. Universal (*)
8. 属性 (如: [type=”text”])
9. 摸拟类别/元素 (如: a:hover)
值得注意的是,虽然ID在技术性上来说比较快,但差异其实很微小。在Windows上的Firefox6上测试,ID的reflow速度还比Class慢。但两者间reflow速度的差距根本不值一提。
注1:reflow是指css在为网页加上样式的过程之一。整个CSS绘制过程会先建立DOM,再进行reflow来确定各元素的位置,最于再进行绘制(render)样式的动作。这里有个reflow Mozilla官网的过程影片。
注2:测试方式是用Steve Sounders制作的工具:css-selectors
复合选择器
你还可以用像是#nav a这种复合(combining)多个选择器的选择器,它的意思是「找到所有在ID为nav的元素下的a元素」。我们以自然语言的阅读方式,来阅读这种复合选择器的方式,通常就是这样用「由左至右」的方式来读,但是浏览器不是这样读的,浏览器是用「由右至左」的方式来理解选择器规则的。
这是为了效率而设计的读取方式,理由可参考这个讨论。于是,浏览器就从DOM树的上至下开始它的剖析查找旅程。
关键选择器 (key selector)
关键选择器就是最靠复合选择器右边的选择器,例如:#nav a,关键选择器就是a,它就是浏览器第一个寻找的规则。是的,浏览器会先找出所有的a元素,还记得上面我们刚讨论过的效率排行吗?此时就是该选择器效率表现的时刻。找出所有的a元素于,接着它会回头去看DOM树,去找看是否有a元素是住在ID为nav的元素之中。
因此,以下的选择器查找规则,就不是非常有效率:
#content *{} |
这样的选择器会先找出「所有」页面上的元素,接着再找是否有任何元素是位于#content底下的。如此的查找成本非常昂贵。
所以,运用这样的知识,我们可以为订定CSS样式做出更好的决策。想像一下,如果你有一个充满大量资料的网页,而你是一个超级大站。在如此页面里,有成千上百个a元素。里头有一小块区域的连结,是专门留给社群连结的区块,它们都放在ID为social的ul元素里,假设里面有Twitter、Facebook、Google+等连结。因此,在这个页面里,我们共有三个社群连结,和其他成千上百个连结。
在这样的页面里,使用以下这个选择器,毫无疑问是非常没有效率的表示法:
#social a{} |
如果要改善这个表示法,我们可以为#social里头的a,加上特定的class,例如:.social-link。但只标上 .social-link 似乎有点违背准确运用CSS类别的好习惯,因为这看来没什么意义,要达成折衷用法,我们可以这样写:
<!-- 略 --> <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 gplus">Google+</a></li> </ul> <!-- 略 --> |
因此,我们的选择器就可以改成:
#social .social-link{} |
这个新的选择器将比对「远低于」先前所需比对的元素,这表示浏览器就可以快速的找到目标元素,并且快速的完成样式的绘制。
过份限制的选择器
接着我们进一步来看其他的最佳化建议。这是一个「过份限制」的选择器例子:
html body .wrapper #content a{} |
这是一个典型限定过了头的选择器例子,其中至少有三个元素是多余的,拿掉于剩下:
#content a{} |
这表示,在浏览器查找到#content于,不用再进一步去找.wrapper、body和html,因为#content是唯一的,找到#content于,其于的查找都是多余的。
再看一个例子:
ul#nav li a{} |
就可改成:
#nav a{} |
知道这样的规则于,你就不会再轻易的写出像下面这种看来很炫,但却没啥效率的表示式了:
div:nth-of-type(3) ul:last-child li:nth-of-type(odd) *{ font-weight:bold } |
另外,jQuery所支持的CSS Selector,读取方式也是从右至左的。
参考文章 http://www.mrmu.com.tw/2011/10/11/writing-efficient-css-selectors/