生成 CSS 规则
同理,CSS 规则树的生成也是类似
1 | Bytes -> character -> tokens -> nodes -> CSSOM |
1 | 1.Conversion:浏览器将获得的HTML内容(Bytes)基于他的编码转换为单个字符 |
举个例子
CSS 代码
1 | body { font-size: 16px } |
DOM 树:
构建渲染书
现在「CSS 树」和「DOM 树」都已经完成,浏览器现在要开始构建渲染树了。
一般情况,「渲染树」和「DOM 树」相对应的, 但是也不定,因为有些不可见的(display:none;)等等不可见的标签会影响「渲染树」
渲染
有了渲染书(render),开始渲染:
分为四个步骤:
1 | 1.计算CSS样式 |
然后,图中的线与箭头表示通过 JS 动态修改了 DOM 或者 CSS,会导致页面「重新布局(Layout)」、「渲染(Repaint)」
什么是回流?
Layout,也叫 Reflow。html 的内容。结构、位置或尺寸发送了变化,需要重新计划样式和渲染树
什么是重绘?
Repaint。元素发生的改变只是影响了元素本身的一些外观之类的(背景,边框颜色等),此时只需要应用新样式绘制这个元素就可以了
回流的成本开销>重绘的成本开销,而且一个节点的回流往往导致子节点以及同级节点的回流。
什么会引起回流?
1 | 1.页面渲染初始化 |
很多浏览器会对回流做优化,会等到数量足够是做一次批处理回流,
但是处理 render 树的直接变化,当获取一些属性的时候,浏览器为了获得正确的值也会触发回流,这样使得浏览器优化无效,包括:
1 | 1.offset(Top/Left/Width/Height) |
回流优化方案
- 减少逐项更改样式,最好一次性更改 style,或者将样式定义为 Class 并一次性更新
- 避免循环操作 dom,创建一个 documentFragment 或者 div,在它上面应用所以 DOM 操作,最后把它添加到 window.document 上
- 避免多次读取 offest 等属性。无法避免则将他们缓存为变量。
- 将复杂的元素绝对定位或者固定定位,使得他们脱离文档流,否则回流代价会很高
举个栗子:
1 | var s = document.body.style; |
简单层与复杂层
上述中的渲染中止步于绘制,但实际上绘制这一步,需要从简单层和复杂层来讲。
- 可以默认只有一个复合图层,所有的 DOM 节点都在这个图层上面,
- 如果开启了硬件加速功能,可以将某个节点转为复合图层
- 复合涂层之间的绘制互不干扰,由 GPU 控制
- 而简单图层中,就算是 absolute 等布局,变化的时候不影响整体的回流,但是由于在同一个图层中,仍然是会影响绘制的,因此做动画的时候性能仍然很低,而复合图层是独立的,所以一般动画推荐使用硬件加速。