过去从来没有考虑过css的解析顺序,今天偶然发现这个问题,记录一下,这篇来自津泊客的同名文章,我自己在语言上做了一些调整。另外可以结合winter老师的一个分享视频进行理解。这里先感谢他们。
1、浏览器的渲染过程
从这张图可以看出,浏览器会将html
文档解析成DOM树
,将css
解析成一套css规则树
,接着将两者组合在一起生成最终的渲染树
。那么他们是如何结合的呢?实际是这样的,循环整个DOM树
,对每一个DOM节点
都在css规则树
上进行遍历。那么效率方面就主要体现在css规则树
的生成方式和遍历方式。例如对下面的css代码,就有从左到右
和从右到左
两种解析方式:
html部分
<div id="div1">
<div class="a">
<div class="b">
...
</div>
<div class="c">
<div class="d">
...
</div>
<div class="e">
...
</div>
</div>
</div>
<div class="f">
<div class="c">
<div class="d">
...
</div>
</div>
</div>
</div>
css部分
#div1 .c .d {}
.f .c .d {}
.a .c .e {}
#div1 .f {}
.c .d {}
如果对上述css
进行从左到右
的解析,可以得到下面的树形图:
如果对上述css
进行从右到左
的解析,可以得到下面的树形图:
那么接下来就讨论一下两种解析顺序的效率吧~
2、两种不同顺序解析的效率分析
首先看第一种方式:我们首先可以看到,在css
里面有一些公共样式的嵌套,例如说,需要找到.c .d
这个样式
的匹配。我们发现在这个样式匹配到多个,这意味着为了不漏掉一些公共样式,我们需要对整个css规则树
进行遍历。这样效率就低了。
然后看第二种方式:从节点数量就可以看出明显差距,第二种遍历方式生成的节点数量少于第一种。并且公共的样式集中在了一块。如:.c .d
只有一条线,这样如果不符合的线既可以直接pass
掉,而不用担心会遗漏样式了。尽管有些样式需要遍历到最后才能确认是不是符合,但是相比第一种方式效率还是高的多。因为前面已经谈到,每一个DOM元素
都需要遍历css规则树
。这样累积起来的效率就差别大了。此外,第二种方式还有一个优点
,由于html元素
生成DOM树
需要时间,而第二种方式是从内向外进行查找的(即先看子节点是否匹配再逐级遍历父节点),就不用担心在css规则树
和DOM树
进行匹配的时候碰到DOM节点
未生成的情况了。
以上。