假设解析 css 是从左向右的匹配,过程是:从 .demo 开始,遍历子节点 ul 和子节点 p,然后各自向子节点遍历。首先遍历到 ul 的分支,然后遍历到 li ,最后遍历到叶子节点a,发现不符合规则,需要回溯到ul节点,再遍历下一个 li ,下一个 a ,假如有 1000 个li ,1000个 a ,就有 1000 次的遍历与回溯,而这一些遍历与回溯都是无用功,还可能会造成性能问题。直到 .demo 向下找到了节点 p ,然后再向下遍历到了 p 下面的节点,找到 span ,这样给 span 加上渲染的样式,然后结束这个分支的遍历。这下才是有用功。
然后看看从右至左的匹配,过程是:先找到所有的最右节点 span ,对于每一个 span ,向上寻找节点 p,由 p 再向上寻找 .demo 的节点,最后找到根元素 html 则结束这个分支的遍历。这样的遍历就不会出现从左向右的匹配时,要遍历 .demo 下面的 ul,遍历 ul 下面的 li ,li 下面的 a 这些无用功的遍历。
显然,两种匹配规则的性能差别非常大。之所以会出现这样的情况,就是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点);而从左向右的匹配规则的性能都浪费在了失败的查找上面,多了很多无用功(比如例子种,遍历 .demo 下面的 ul,遍历 ul 下面的 li ,li 下面的 a )。
可能很多人都会被问到过,浏览器解析 css 的时候,为什么是从右往左解析,而不是从左往右解析?关于这个问题,通俗一点的解析就是:如果 css 从左往右解析,浏览器会更累。
为什么这么说呢?首先给出下面的代码
根据 css 代码
假设解析 css 是从左向右的匹配,过程是:从 .demo 开始,遍历子节点 ul 和子节点 p,然后各自向子节点遍历。首先遍历到 ul 的分支,然后遍历到 li ,最后遍历到叶子节点a,发现不符合规则,需要回溯到ul节点,再遍历下一个 li ,下一个 a ,假如有 1000 个li ,1000个 a ,就有 1000 次的遍历与回溯,而这一些遍历与回溯都是无用功,还可能会造成性能问题。直到 .demo 向下找到了节点 p ,然后再向下遍历到了 p 下面的节点,找到 span ,这样给 span 加上渲染的样式,然后结束这个分支的遍历。这下才是有用功。
然后看看从右至左的匹配,过程是:先找到所有的最右节点 span ,对于每一个 span ,向上寻找节点 p,由 p 再向上寻找 .demo 的节点,最后找到根元素 html 则结束这个分支的遍历。这样的遍历就不会出现从左向右的匹配时,要遍历 .demo 下面的 ul,遍历 ul 下面的 li ,li 下面的 a 这些无用功的遍历。
显然,两种匹配规则的性能差别非常大。之所以会出现这样的情况,就是因为从右向左的匹配在第一步就筛选掉了大量的不符合条件的最右节点(叶子节点);而从左向右的匹配规则的性能都浪费在了失败的查找上面,多了很多无用功(比如例子种,遍历 .demo 下面的 ul,遍历 ul 下面的 li ,li 下面的 a )。
知道了 CSS 是这样渲染的,有什么优化的建议吗?
1.CSS 能少写尽量少写,比如利用 CSS 某些属性继承的特性,或者抽取公用样式。减少CSS代码,使遍历查找的分支尽量少
2.CSS 路径尽量短写,尽量不要超过 4 层,比如上面例子 .demo p span 可以写成 .demo span 。这样找到 span 之后可以直接找 .demo 不需要经过 p。