从性能的角度看CSS选择器

CSS选择器的解析原理与对性能的影响

解析原理

一个以前不知道的事实:

CSS选择器是从右向左匹配的

看了一篇文章发现这个细节以前没注意过,一直以为是跟人一样是以从左向右的顺序查找的。

比如下面这段CSS:

1
2
3
.sample table td {
color: red;
}

以前认为应该是先找到sample类的元素,再找到子元素中的所有table,再找到table中的所有td,最后应用红色文字的样式。

而正确的顺序是先找到所有td元素,检查祖先元素是否有table,再检查table的祖先元素是否具有sample类。

CSS选择器是像这样从右向左匹配的。

最右边的选择器被称为关键选择器(key selector)

写法优化

假如有下面一段HTML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- 需要文字变红的表格 -->
<div class="sample">
<table>
<tr>
<td>hoge</td>
<td>hogehoge</td>
</tr>
<tr>
<td>fuga</td>
<td>fugafuga</td>
</tr>
</table>
</dvi>
<!-- 文本保持黑色即可的表格 -->
<div class="sample2">
<table>
<tr>
<td>hoge</td>
<td>hogehoge</td>
</tr>
<tr>
<td>fuga</td>
<td>fugafuga</td>
</tr>
</table>
</div>

第一部分的CSS代码会将sample类下表格td元素的文本变为红色,它会先寻找DOM中的所有td元素,然后是table元素,最后确认是否具有sample类。

不过sample2类下的表格文本需要保持黑色,因此sample2类中的td元素根据不需要被查找。这样一来显然会产生多余的开销。

当sample2类中的td元素数量变多时,有可能会产生性能上的问题。

1
2
3
.red {
color: red;
}

可能你已经想到会这么做了,果然最好的方法就是给想要设置为红色文本的cell加一个样式为红色的class。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- 需要文本变红的表格 -->
<div class="sample">
<table>
<tr>
<td class="red">hoge</td>
<td class="red">hogehoge</td>
</tr>
<tr>
<td class="red">fuga</td>
<td class="red">fugafuga</td>
</tr>
</table>
</dvi>
<!-- 文本保持黑色即可的表格 -->
<div class="sample2">
<table>
<tr>
<td>hoge</td>
<td>hogehoge</td>
</tr>
<tr>
<td>fuga</td>
<td>fugafuga</td>
</tr>
</table>
</div>
  • 关键选择器可能会直接影响性能
  • 关键选择器的查找范围要尽量小一些(不匹配不相关的DOM)
  • 关键选择器的查找范围会影响开销

性能比较

参考一

不同选择器在三种浏览器上1500个div中的匹配性能比较

选择器类型 Firefox 15.0 Chrome 19.0.1084.1 IE 8
class selectors (.classname) 35ms 100ms 35ms
class selectors, more specific (div.classname) 36ms 110ms 37ms
class selectors, even more specific (div div.classname) 40ms 115ms 40ms
id selectors (#id) 35ms 99ms 35ms
id selectors, more specific (div#id) 35ms 105ms 38ms
id selectors, even more specific (div div#id) 40ms 110ms 39ms
class selectors, with attribute (.class[title=”ttl”]) 45ms 400ms 2000ms
class selectors, more complex attribute (.class[title~=”ttl”]) 45ms 1050ms 2200ms

虽然数据有些老,可以看出类选择器、id选择器和元素选择器没什么问题。

当使用指定属性选择器时,在极端情况下渲染速度会非常慢(少用为好)。

参考二

不同选择器的渲染速度排序

  1. ID, e.g. #header
  2. Class, e.g. .promo
  3. Type, e.g. div
  4. Adjacent sibling, e.g. h2 + p
  5. Child, e.g. li > ul
  6. Descendant, e.g. ul a*
  7. Universal, i.e. *
  8. Attribute, e.g. [type=”text”]
  9. Pseudo-classes/-elements, e.g. a:hover

果然类选择器、id选择器和元素选择器占了前几位。

参考三

需要谨慎使用、开销昂贵的属性

  • border-radius
  • box-shadow
  • transform
  • filter
  • :nth-child
  • position: fixed;

不建议使用的属性

  • *
  • [disabled]
  • [type=“text”]

参考

文章目录
  1. 1. 解析原理
  2. 2. 写法优化
  3. 3. 性能比较
    1. 3.1. 参考一
    2. 3.2. 参考二
    3. 3.3. 参考三
  4. 4. 参考
|