浏览器渲染流程:从 HTML 到屏幕像素,中间到底发生了什么
这篇文章基于旧博客中的“浏览器工作原理”内容重写,重点解释浏览器如何把 HTML 变成最终可见页面,以及 reflow、repaint 和 transform 的关系。
浏览器渲染流程是一个很典型的面试题。
很多人会记住几个关键词,比如 DOM、CSSOM、布局、重排、重绘,但如果要把整个流程完整讲出来,还是很容易断掉。
这篇文章我想重新梳理一下这个过程,重点不是记术语,而是搞清楚浏览器到底是怎么一步一步把页面画出来的。
先有一个总览
当浏览器收到一份 HTML 文档后,页面并不是瞬间出现的。
中间大致要经过这些阶段:
- 解析 HTML
- 解析 CSS
- 计算样式
- 布局
- 分层
- 绘制
- 分块
- 光栅化
- 合成并显示到屏幕
这些阶段前后衔接,每一步的输出都会成为下一步的输入。
第一步:解析 HTML
浏览器拿到 HTML 后,会开始解析标签结构,并逐步生成 DOM 树。
在这个过程中还会遇到两类关键资源:
CSS
如果遇到外部 CSS,浏览器会下载并解析它,最后形成 CSSOM。
CSS 不会阻塞 HTML 的继续解析,但它会影响后续渲染,因为浏览器需要样式信息来计算元素最终怎么显示。
JavaScript
如果遇到同步脚本,HTML 解析通常会暂停,等脚本下载并执行完之后再继续。
原因很简单:JavaScript 可能会直接修改当前 DOM 结构,如果 DOM 还在一边生成一边被脚本改,就很容易出现状态不一致的问题。
所以从渲染角度看:
- CSS 更像“可以并行准备的资源”
- JS 更像“可能打断当前解析流程的任务”
第二步:样式计算
当 DOM 和 CSSOM 准备好后,浏览器会为 DOM 树上的每个节点计算最终样式,也就是 Computed Style。
这一步的意义是:把作者写的 CSS 规则,真正转换成当前节点的最终可用值。
例如:
red可能会变成rgb(255, 0, 0)em可能会换算成具体的px- 层叠、继承、默认值会一起参与最终结果计算
这一步结束之后,可以理解为:浏览器已经知道“每个节点该长什么样”。
第三步:布局
知道样式还不够,还得知道元素具体在页面上占多大、放在哪里。
所以接下来浏览器会做布局计算。
布局阶段会确定元素的几何信息,比如:
- 宽高
- 位置
- 相对包含块的偏移
这一步的产物通常叫布局树。
DOM 树和布局树不是一回事
这是一个很重要的点。
并不是 DOM 里的每个节点都会进入布局树。
例如:
display: none的元素没有几何信息,所以不会出现在布局树里- 某些伪元素虽然不在 DOM 树中,但有几何信息,可能会进入布局树
所以布局树更像是一棵“真正参与几何计算和页面排版”的树。
第四步:分层
布局完成后,浏览器不会直接把所有东西一次性画完,而是会先决定哪些内容应该放到不同的图层中。
分层的核心目的,是为了提高后续更新效率。
因为如果某一层发生变化,浏览器不一定需要把整个页面都重新处理,只需要重算受影响的那一层。
常见会影响分层的因素包括:
- 堆叠上下文
transformopacity- 某些动画效果
will-change
第五步:绘制
分层之后,浏览器会为每一个图层生成绘制指令。
你可以把它理解成:浏览器在写一份“绘图说明书”,告诉后续流程这个层里有哪些内容,应该怎么画出来。
这一步还不是最终像素,只是绘制命令。
第六步:分块与光栅化
接下来,浏览器会把图层拆成更小的区域,也就是分块。
为什么要这样做?
因为页面通常很大,没必要每次都把整层一次性处理完。拆成块之后,可以更灵活地优先处理当前视口附近的内容。
然后进入光栅化阶段。
光栅化的本质,是把前面那些绘制指令真正转换成位图像素。
这一步通常会借助 GPU,更适合大规模像素处理。
第七步:合成与显示
当每一层、每一块都准备好之后,合成线程会根据它们的位置信息,把这些位图组合起来,最终交给 GPU 输出到屏幕。
到这里,用户才真正看到页面。
什么是 reflow
reflow 常被翻译成重排,本质上就是重新计算布局。
只要某个改动会影响元素几何信息,就可能触发 reflow,比如:
- 宽高变化
- 字体大小变化
- 定位相关属性变化
- 元素增删导致文档流变化
reflow 的代价通常比较高,因为它会影响后续很多阶段。
布局一变,后面可能还要重新分层、重新绘制、重新合成。
什么是 repaint
repaint 是重绘。
它不一定会重新布局,但会重新生成绘制结果。
比如只改了颜色、背景、阴影之类的可见样式,几何信息没变,那么通常不会重新布局,但仍然需要重新绘制。
所以:
- reflow 一定会引起 repaint
- repaint 不一定会引起 reflow
为什么 transform 的性能通常更好
这是面试里也很常见的追问。
原因不在于 transform 这个属性本身“更高级”,而在于它通常不会影响布局和绘制阶段的核心结果。
很多时候它只会影响最终合成阶段的变换。
也就是说:
- 不重新算布局
- 不重新生成整套绘制指令
- 主要在合成阶段处理
这就是为什么位移、缩放、旋转等动画,通常更推荐使用 transform 和 opacity。
面试时可以怎么讲
如果真的在面试里回答这个问题,我会尽量按下面的顺序讲:
- 浏览器收到 HTML 后会先解析 DOM,同时准备 CSSOM
- 之后做样式计算,得到每个节点的最终样式
- 再做布局,得到元素的几何信息
- 然后根据布局结果进行分层
- 每个层生成绘制指令
- 图层再被分块、光栅化
- 最后由合成线程和 GPU 把它们绘制到屏幕上
- 如果改动影响几何信息会触发 reflow,如果只影响外观通常是 repaint
transform更高效,是因为很多情况下它主要发生在合成阶段
这样讲,结构会比较完整,也更容易继续接住后面的追问。