尽管css选择器效率问题已经不是什么新鲜问题,但是我觉得还是有必要拿出来认真分析一下。之前只是看到别人这么写我也跟着这么写,并没有想清楚问什么要这样写?这样写真的能提高页面渲染效率吗?尽管自己技术不怎么样,但还是需要拿出一种打破砂锅问到底的决心来深究一下css选择器效率问题,通过自己写个demo亲自实践来加深一下对这个问题的理解。
事情的经过是这样子的,在之前的博文CSS选择器总结中介绍了各种不同的css选择器,顿时觉得css的世界很精彩,可以有很多种不同的写法,想怎么写就怎么写,于是就有了这种代码
.wrapper ul li a{color:red;……}
.wrapper .list p.name{margin:10px 0;……}
* {margin:0;padding:0}
……
写完这样样式后,自我感觉还不错,至少页面能呈现出来。可是直到有一天突然发现
CSS选择器从右向左的匹配规则
我的世界瞬间崩塌了,因为根据阅读习惯在编写CSS的时候也会自然而然是从左向右逐渐细化。顿时很想搞清楚浏览器在将DOM tree变成render tree的时候css规则是如何匹配的?于是查了这么些资料:
- Why do browsers match CSS selectors from right to left?
- Writing Efficient CSS: Understand Your Selectors
- 编写高效的 CSS
看了这么多我的理解是从右往左匹配会首先过滤掉一大批不符合规则的样式,从而使得效率更高。举个例子
.wrapper .list a .demo{……}
如果从左往右匹配会先找到.wrapper,然后再找到里面很多的.list,在往里找直到找到那个.demo,查找的越深,过滤掉的也就越多,在这个查找的过程中会有很多没用的样式也被遍历过,这里就导致匹配的效率很低。
如果从右向左匹配会首先过滤掉不是.demo的元素,在依次往上查找,越往上过滤掉的也就越少,这样效率明显比从左往右匹配要高很多
弄明白了从右向左匹配的规则那么我们要如何写才能让浏览器更快的匹配到呢?
浏览器在面对众多的CSS样式代码时并不是毫无规则的一个一个匹配,而是先将样式规则分为四个主要类别:
- ID 规则 这第一个类别包含了那些将 ID 选择器作为关键选择器的规则。
- Class 规则 如果一个规则将一个 class 明确作为它的关键选择器,那么它就属于该类别。
- 标签规则 如果一条规则将一个标签作为它的关键选择器,那么这条规则就属于该类别。
- 通用规则 不属于上面那些类别的规则都属于这个类别。
并引入关键选择器的概念(选择器最后的那部分)
.wrapper ul li a{color:red;……} /* 关键选择器为a */
.wrapper .list p.name{margin:10px 0;……} /* 关键选择器为.name */
根据关键选择器属于哪类再在这一类中查找,从而达到更快匹配的目的。那么问题来了,怎样写才能达到高效呢?
CSS选择器效率从高到低的排序如下:
- ID选择器 比如#header
- 类选择器 比如.promo
- 元素选择器 比如 div
- 兄弟选择器 比如 h2 + p
- 子选择器 比如 li > ul
- 后代选择器 比如 ul a 7. 通用选择器 比如 *
- 属性选择器 比如 type = “text”
- 伪类/伪元素选择器 比如 a:hover
以上引用自Steve Souders的Even Faster网站
在实际使用中我们尽量选择高效一点的选择器,但是有一点很难避免那就是组合选择器的使用,一般都会用到。在使用组合选择器时我们需要注意一下几点:
- 如果规则拥有ID选择器作为其关键选择器,则不在需要添加其他规则了,因为ID是唯一的。
- 差 .wrapper button#backButton {…}
- 好 #backButton {…}
- 不要用标签名限定 class 规则,这会有损灵活性
- 差 .wrapper p.name{…}
- 好 .wrapper .name{…}
- 避免使用过度限制选择器(最好不要超过3层)
- 差 body .wrapper .content .list {}
- 好 .content .list{}
- 避免后代选择器,后代选择器是 CSS 中性能耗用最大的选择器。
- 差 ul li a{}
- 好 .list .list-content{}
- 依赖继承
本来想写几个demo展示出不同选择器的效率的,但是不好演示,大家可以看看CSS selector performance
这篇文章中介绍了20中不同的选择器的执行效率问题。
结合自己的实践经历,在编写CSS规则时需注意以下几点:
- 嵌套层级最好不要超过3层
- 避免使用标签选择器,尽可能使用具体的类名
- 不要给关键选择器添加多余的规则
CSS选择器在性能提升上尽管相对于js等提升空间不大,但在大型项目中高效率的css选择器的性能优势就能得到展现
原文链接:http://www.jesse131.cn/blog/2016/12/05/HTML-CSS/CSS_selector_performance.html