浏览器的渲染流程,从 URL 到像素
浏览器从输入 URL 到页面渲染出来,中间经历的过程我以前大概能说个七八成,但总有些细节是模糊的。这次整理笔记,干脆把整个链路理了一遍。
主要阶段
1. 构建 DOM 树
浏览器收到 HTML 后,会逐字节解析,把标签转成节点,再生成 DOM 树。过程中如果遇到 <script> 标签,会暂停解析去下载和执行脚本——这也是为什么建议把 JS 放在 body 底部。
2. 构建 CSSOM 树
CSS 的解析和 HTML 类似,但 CSS 是"层叠"的,涉及到优先级计算,比 HTML 解析复杂一些。不过 CSS 解析不会阻塞 DOM 树构建,但会阻塞渲染——因为浏览器需要等 CSSOM 就绪才能确定每个元素的样式。
3. 生成渲染树
DOM 树 + CSSOM 树 = 渲染树。但渲染树不是简单的合并,它会过滤掉不可见的节点(比如 display: none 的元素),只保留需要绘制的内容。
4. 布局
确定每个元素的位置和大小。这个过程是递归的——父元素的位置会影响子元素,子元素的大小也会反过来影响父元素。所以布局阶段会从根节点开始,逐级计算。
5. 绘制
把布局结果转换成屏幕上的像素。浏览器会把绘制内容分层(比如固定定位的元素单独一层),然后按层绘制,最后合成。
关键优化点
- CSS 放在 head 里:尽早开始 CSSOM 构建,缩短阻塞渲染的时间
- JS 放在 body 底部,或用 defer/async:避免阻塞 DOM 解析
- 减少回流:回流是布局阶段的重新计算,成本很高。能用 transform 就尽量不用 top/left
回流和重绘的区别
- 回流:元素的尺寸、位置变了,浏览器需要重新计算布局。比如修改 width、margin、padding。
- 重绘:元素的样式变了但布局没变,比如修改 color、background。
回流的代价比重绘大得多,因为回流之后一定会有重绘。所以性能优化的一个核心思路就是:尽量减少回流。
整理完这个流程,我对"script 放哪里""为什么用 transform 更好""CSS 加载会不会阻塞"这些面试题的理解,就不再是背答案了,而是能从头推到尾。
