浏览器渲染原理
面试速答(30 秒版 TL;DR)
- 浏览器渲染不是“拿到 HTML 直接显示”,而是要经历:解析 HTML 构建 DOM、解析 CSS 构建 CSSOM、合成 Render Tree、Layout、Paint、Composite。
- CSS 会阻塞渲染,JS 可能阻塞解析和渲染;所以首屏性能优化本质上是在缩短渲染关键路径(Critical Rendering Path)。
- 真正容易卡的地方通常不是“下载慢”一个点,而是:阻塞资源太多、主线程太忙、频繁布局和绘制。
- 一句话记忆:先把结构和样式算出来,再算位置,再画出来,最后交给合成线程上屏。
心智模型:浏览器在做两件事
你可以把浏览器渲染理解成两个连续问题:
- 页面长什么样? 这一步要解析 HTML、CSS,确定节点、样式、可见性。
- 页面怎么摆、怎么画、怎么上屏? 这一步要做布局、绘制、图层合成。
常见误区是把“解析”“布局”“绘制”混成一个动作。面试里最好拆开说,因为不同优化手段针对的是不同阶段。
关键流程:从字节到像素
1. 解析 HTML,构建 DOM
- 浏览器把 HTML 字节流转成 Token,再生成 DOM 树。
- DOM 描述的是文档结构,不负责最终样式和位置。
- HTML 解析通常是增量式的,边下载边解析,不一定等整个 HTML 下载完才开始。
2. 解析 CSS,构建 CSSOM
- CSSOM 描述的是每个节点最终可能应用的样式规则。
- CSS 会影响后续布局和绘制,因此浏览器通常要等关键 CSS 到位,才能安全进入后续阶段。
- 所以常说 CSS 是渲染阻塞资源。
3. 合成 Render Tree
- Render Tree 不是 DOM 的简单复制。
- 像
display: none这样的节点不会进入 Render Tree。 - 伪元素、匿名盒模型结构可能会进入 Render Tree。
4. Layout(布局 / 回流)
- 根据 Render Tree 和盒模型规则,计算每个可见元素的几何信息:
- 位置
- 宽高
- 盒子之间的关系
- 这一步是后续绘制的前提。
5. Paint(绘制 / 重绘)
- 把每个节点该怎么画记录成绘制指令。
- 例如背景色、边框、文字、阴影、图片。
6. Composite(合成)
- 浏览器可能会把部分内容拆成独立图层。
- 合成线程把这些图层按顺序拼起来,最终显示到屏幕。
- 这也是为什么
transform、opacity这类属性通常更适合做动画。
哪些资源会阻塞渲染
CSS 为什么会阻塞
因为浏览器在不知道最终样式前,无法可靠地做布局和绘制。如果先画出来、后面样式又变,会导致闪烁和重复计算。
JS 为什么会阻塞
因为 JS 可以直接改 DOM 和 CSSOM:
<script>
document.body.innerHTML = '<h1>new content</h1>'
</script>
如果浏览器一边解析、一边渲染,而 JS 又随时改结构,状态就会不一致。所以普通同步脚本会阻塞 HTML 解析;如果脚本依赖样式信息,也可能间接等待 CSS。
一个面试很好用的链路表达
先记住关键路径:请求资源、构建树、布局绘制,然后才有首屏可见。
面试时你可以总结为:
首屏慢,本质上不是单点问题,而是关键路径太长。要么资源来得慢,要么主线程被阻塞,要么渲染阶段反复重算。
典型优化抓手
1. 缩短关键资源链路
- 减少首屏必须下载的 CSS/JS
- 关键 CSS 尽量提前
- 非关键 JS
defer/ 懒加载 - 图片按需加载,首屏图高优先级
2. 减少主线程压力
- 避免首屏执行过多同步 JS
- 重计算丢到 Worker
- 大列表做虚拟滚动
3. 减少渲染成本
- 避免频繁读写布局属性
- 动画优先
transform/opacity - 控制 DOM 深度和复杂样式
典型题 & 标准答法
Q1:浏览器渲染页面的过程是什么?
答:浏览器先解析 HTML 构建 DOM,解析 CSS 构建 CSSOM,然后把两者合成 Render Tree。接着进行 Layout 计算元素几何信息,再进行 Paint 生成绘制指令,最后通过 Composite 把图层合成并显示到屏幕上。这里 CSS 会阻塞渲染,JS 可能阻塞解析和渲染,所以性能优化重点是缩短渲染关键路径。
Q2:为什么 CSS 会阻塞渲染?
答:因为 CSS 会影响元素最终样式和布局。如果样式还没确定,浏览器无法安全地计算位置和绘制内容。为了避免错误绘制和反复重算,浏览器通常会等待关键 CSS 解析完成后再继续后续渲染流程。
Q3:为什么 transform 动画通常比改 top/left 更流畅?
答:top/left 往往会触发布局和绘制,而 transform 更容易只走合成阶段,不必每一帧都重新 Layout 和 Paint,所以更容易保持流畅。
常见追问
- DOM 和 Render Tree 有什么区别?
display: none和visibility: hidden对渲染流程有什么影响?async和defer对渲染链路分别有什么影响?- 为什么“首屏 JS 太多”会让 LCP 变差?
易错点
- 不要把 DOM 构建 和 Render Tree 构建 说成一回事。
- 不要把 Layout 和 Paint 混为一谈。前者算位置尺寸,后者负责画。
- 不要机械地说“CSS 会阻塞 DOM 解析”。更准确地说:CSS 主要阻塞渲染,JS 是否阻塞解析取决于脚本加载与执行方式。
速记要点
- DOM 决定结构,CSSOM 决定样式,Render Tree 决定可渲染对象。
- Layout 算位置,Paint 负责画,Composite 负责上屏。
- 性能优化重点不是背流程,而是知道瓶颈卡在哪一段。