浏览器在接收到HTML文档后,会通过一系列步骤将其转换为用户可见的网页。这个过程包括:解析、样式计算、布局(reflow)、分层、绘制(Repaint)、分块和光栅化、合成和显示。每个阶段都紧密相连,上一阶段的输出成为下一阶段的输入。
HTML解析与预解析
- HTML解析:主线程解析HTML文档,构建DOM树
- CSS解析:预解析线程下载并解析CSS,构建CSSOM树
- JS执行:遇到
<script>
标签时,HTML解析暂停,直到脚本下载并执行完毕。这是因为JavaScript可能修改DOM结构,除非标记为async/defer
。 - 预解析:为了提高效率,浏览器使用预解析线程预先加载外部资源(如CSS、JS文件),避免阻塞主线程。
样式计算
- 在DOM树和CSSOM树的基础上,计算出每个节点的具体样式(Computed Style),这个过程包括:继承样式、层叠样式、单位转换(em→px,百分比→绝对值等)、浏览器默认样式。
布局(Reflow、回流)
- 计算每个元素的几何信息(宽高、位置等),生成布局树(Layout Tree或Render Tree)。此过程如果被触发(例如,页面尺寸改变或内容更新),称为回流(reflow)。为了避免频繁的回流操作影响性能,浏览器通常会批量处理这些请求。
- DOM树与布局树的差异:
display: none
的元素不会出现在布局树中,伪元素会出现在布局树中。
分层
- 依据复杂的策略将页面分成多个图层,分层目的是优化渲染性能(独立层可以单独重绘),比如滚动条、堆叠上下文、transform、opacity等。
绘制(Repaint、重绘)
- 对每个图层生成绘制指令集,描述如何渲染。当需要重新绘制某部分(例如颜色变化)但不影响布局时,这被称为重绘(repaint)。绘制工作由主线程完成,但实际绘制由合成线程处理
光栅化与合成
- 将图层分割成小块,并快速地转化为位图形式(光栅化)。合成线程负责管理这些位图的显示顺序和变换(如旋转、缩放),然后提交给GPU完成最终的屏幕渲染。
Transform 的高效性
- 独立合成层:transform属性通常会创建一个新的合成层,这个层可以独立于其他层进行处理。
- GPU加速:现代浏览器会将transform动画交给GPU处理,GPU擅长并行处理这类计算。
- 避免回流和重绘:transform动画不会影响文档流,因此不会触发昂贵的回流计算。
- 合成线程处理:transform变化发生在合成阶段,不需要主线程参与,避免了JavaScript和样式计算的阻塞。
- 16ms优化:浏览器针对transform和opacity变化进行了特殊优化,能更好地配合60fps(每帧16ms)的渲染节奏。
- 最小化重绘区域:transform变化只需要重绘受影响图层,而不是整个页面。