前段壁咚!浏览器的渲染机制之CSS

  • HTML Parser 生成的 DOM 树
  • 其二,CSS Parser 生成的 Style Rules

Webkit CSS 解析器

  1. 通过调用 CSSStyleSheetparseString 函数,将上述 CSS 解析过程启动,解析完一遍后,把 Rule 都存储在对应的 CSSStyleSheet 对象中
  2. 目前规则依然是不易于处理的,还需要将之转换成 CSSRuleSet 。也就是将所有的纯样式规则存储在对应的集合当中,这种集合的抽象就是 CSSRuleSet
  3. CSSRuleSet 提供了一个 addRulesFromSheet 方法,能将 CSSStyleSheet 中的 rule 转换为 CSSRuleSet 中的 rule
  4. 基于这些个 CSSRuleSet 来决定每个页面中的元素的样式

选择器的解析顺序

排版引擎解析 CSS 选择器时是从 右往左 解析

  1. HTML 经过解析生成 DOM Tree;而在 CSS 解析完毕后,解析的结果将与 DOM Tree 的内容一起进行分析建立一棵 Render Tree,最终用来进行绘图。Render Tree 中的元素(WebKit 中称为「renderers」,Firefox 下为「frames」)与 DOM 元素相对应,但非一一对应:一个 DOM 元素可能会对应多个 renderer,如文本折行后,不同的「行」会成为 render tree 种不同的 renderer。也有的 DOM 元素被 Render Tree 完全无视,比如 display:none 的元素。
  2. 在建立 Render Tree 时(WebKit 中的「Attachment」过程),浏览器要为每个 DOM Tree 中的元素根据 CSS 的解析结果(Style Rules)来确定生成怎样的 renderer。对于每个 DOM 元素,必须在所有 Style Rules 中找到符合的 selector 并将对应的规则进行合并。选择器的「解析」实际是在这里执行的,在遍历 DOM Tree 时,从 Style Rules 中去寻找对应的 selector。
  3. 所有样式规则可能数量很大,而且绝大多数不会匹配到当前的 DOM 元素(因为数量很大所以一般会建立规则索引树),所以有一个快速的方法来判断「这个 selector 不匹配当前元素」就是极其重要的。
  4. 如果正向解析,例如 「div div p em」 ,我们首先就要检查当前元素到 html 的整条路径,找到最上层的 div,再往下找,如果遇到不匹配就必须回到最上层那个 div,往下再去匹配选择器中的第一个 div,回溯若干次才能确定匹配与否,效率很低。

应用

  1. id是唯一的,id选择器的权重也是较高的,所以不要写成 p#id1 这个亚子降低解析效率
  2. 避免 深层次 的子元素选择器
  3. 慎用 ChildSelector
  4. 慎用 attribute selector(Vue的scoped基于此实现的)
  5. 用依赖继承,如果某些属性可以继承

前段壁咚!浏览器的渲染机制之CSS