举个例子
|
上述代码在css运行时,是从左往右匹配呢,还是从右往左匹配。
如果不知道匹配规则,可能的理解是从左向右匹配: 先找到.mod-nav,然后逐级匹配h3、span,在这个过程中如果遍历到叶子节点都没有匹配就需要回溯,继续寻找下一个分支。
但事实上,CSS选择器的读取顺序是从右向左。
还是上面的选择器,它的读取顺序变成:先找到所有的span,沿着span的父元素查找h3,中途找到了符合匹配规则的节点就加入结果集;如果直到根元素html都没有匹配,则不再遍历这条路径,从下一个span开始重复这个过程(如果有多个最右节点为span的话)。
为什么从右向左的规则要比从左向右的高效?
|
假如DOM的结构如上图,匹配规则是 .mod-nav h3 span
。
若从左向右的匹配,过程是:从 .mod-nav
开始,遍历子节点 header
和子节点 div
,然后各自向子节点遍历。在右侧 div
的分支中,最后遍历到叶子节点 a
,发现不符合规则,需要回溯到 ul
节点,再遍历下一个 li-a
,假如有1000个 li
,则这1000次的遍历与回溯会损失很多性能。
再看看从右至左的匹配:先找到所有的最右节点 span
,对于每一个 span
,向上寻找节点 h3
,由h3再向上寻找class=mod-nav的节点,最后找到根元素 html
则结束这个分支的遍历。
很明显,两种匹配规则的性能差别很大。之所以会差别很大,是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点);而从左向右的匹配规则的性能都浪费在了失败的查找上面。
当然这是比较明显情况,如果在叶子上存在多个不符合条件的 span
,从右向左的规则也会走一些弯路(这时就需要优化 CSS
选择器了)。但平均来说它还是更高效,因为大多时候,一个 DOM
树中,符合匹配条件的节点(如 .mod-nav h3 span
)远远远远少于不符合条件的节点。
jQuery
从1.3版本开始使用的 Sizzle
引擎,它按照了 CSS
选择器的匹配规则(从右至左)进行DOM元素的查找与匹配(当然其中做了很多优化),性能得到了很大的提升。
参考
- 本文作者: luckyship
- 本文链接: https://luckyship.github.io/2021/01/16/2021-01-16-css-match-principle/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!