你每天用浏览器打开网页,输入一个网址,按下回车,几秒后页面就出现在屏幕上。这个过程中,你的电脑在背后完成了一场极其精密的工程协作。
这篇文章不讲网络请求(DNS、TCP握手),我们聚焦一个更神奇的部分:当数据下载完毕后,浏览器是如何把一堆HTML、CSS和JavaScript变成你屏幕上那些漂亮像素的。
第一步:HTML解析——从文本到树
浏览器收到的第一个东西通常是HTML文件。但HTML只是一堆带尖括号的文本,电脑不懂什么是
。
所以浏览器的渲染引擎(Chrome用的叫Blink,Safari用WebKit,Firefox用Gecko)会启动一个叫HTML解析器的工具。它的工作是把原始的HTML字符串转化成一种叫DOM(Document Object Model,文档对象模型)的树状结构。
想象你在写一篇文章的大纲:
文章
├── 第一章
│ ├── 第一段
│ └── 第二段
├── 第二章
│ └── 第一段
DOM树就是这种结构。每个HTML标签变成一个节点,嵌套关系形成父子关系。浏览器最终持有这样一棵巨大的树,树的每个节点都代表页面上的一个元素。
有意思的是,HTML解析器有一个非常聪明的设计:容错机制。
如果你写HTML时忘了关闭某个标签(比如写了
第二步:CSS解析——样式的树
光有结构还不够,网页还需要样式。CSS定义了每个元素应该长什么样——颜色、字体、大小、位置。
浏览器会解析所有的CSS(包括外部样式表、内联样式、行内样式),构建另一棵树:CSSOM(CSS Object Model)。
CSSOM跟DOM的结构类似,但有一个重要的不同点:它包含层叠(cascade)信息。
层叠是CSS的核心机制。当多个样式规则作用于同一个元素时,谁说了算?比如一个
标签同时被三个CSS规则覆盖:外部样式表说颜色是蓝色,内联样式表说颜色是红色,
标签上直接写style="color: green"。
CSS有一套复杂的优先级计算规则(称为特异性,specificity),用来决定最终哪个规则生效。简单来说:越具体的规则优先级越高。内联样式 > ID选择器 > 类选择器 > 标签选择器。
所以当你写CSS发现某个样式没生效,大概率是优先级被别的规则覆盖了。
第三步:Render Tree——两棵树合并成一棵
有了DOM(结构)和CSSOM(样式),浏览器要把它们合并成一棵新的树:渲染树(Render Tree)。
渲染树只包含可见的元素。如果一个元素的CSS是display: none,它就不会出现在渲染树中。但visibility: hidden或opacity: 0的元素不同——它们虽然看不见,但占据空间,所以仍然在渲染树里。
这一步也包含一个非常耗时的操作:样式计算。浏览器要遍历每一个DOM节点,计算它最终应用的所有CSS属性值。现代浏览器做了大量优化,比如Chrome用哈希表缓存已计算的结果,避免重复计算相同规则的节点。
第四步:布局——计算位置
有了渲染树,浏览器知道了页面有哪些元素和每个元素长什么样,但还不知道每个元素在哪里。
布局(Layout,在Chrome里也叫Reflow)就是计算每个元素在页面上的精确位置和尺寸。
这是一个从根节点开始的递归过程。浏览器从开始,根据CSS的盒子模型——内容区 加 内边距 加 边框 加 外边距——一步步计算出所有元素的位置。
如果一个元素的宽度是父元素的50%,那浏览器必须先知道父元素的宽度,才能算出子元素的实际像素值。所以布局必须是从上到下、从左到右的。
这也就是为什么改变一个元素的宽度可能导致它后面所有元素的位置都改变——这就是重排(Reflow)的本质。如果CSS动画改变了某个元素的位置,浏览器可能需要重新计算整个页面或部分区域的布局。重排是一个非常昂贵的操作,这也是为什么transform和opacity比left和width更适合做动画——前者不会触发重排。
第五步:绘制——填色
布局完成后,浏览器知道了每个元素的位置和尺寸。接下来是绘制(Paint):把元素画成实际的像素。
这一步浏览器会把渲染树拆分成多个图层。就像Photoshop里不同图层可以独立编辑一样,浏览器也为不同的页面区域分配独立的层。哪些区域会成为独立层?比如有position: fixed或position: sticky的元素、使用CSS 3D变换(transform: translateZ(0))的元素、有will-change属性的元素。
分层的目的是:当某个区域变化时,浏览器只需要重绘那一层,而不是整个页面。
绘制完成后,浏览器有了很多张位图,每张对应一个图层。
第六步:合成——最后的拼装
最后一步是合成(Composite):浏览器把这些图层按正确的顺序组合起来,得到最终的画面。就像动画制作中把背景、角色、前景分别绘制再叠在一起。
合成是在GPU(图形处理器)上完成的。这也是为什么现代网页动画越来越流畅——大量计算被转移到了专门的硬件上。
最终,合成的图像被发送到屏幕缓冲区,你的显示器刷新一次,一个像素完整的页面就诞生了。
性能启示
理解了渲染流水线,就能明白为什么有些网页操作会卡顿了:
- 改变宽高或位置 → 触发重排(Layout) → 最慢,后续的绘制和合成都要重新做
- 改变背景色或文字颜色 → 触发重绘(Paint) → 中等,不需要重新布局,但需要重新绘制
- 使用transform或opacity做动画 → 只触发合成(Composite) → 最快,在GPU上完成
这也是为什么很多前端性能优化建议多用transform替代left。它不是在炫技,是实实在在的工程优化。
总结
从你按下回车到页面显示在屏幕上,浏览器完成了一次六步的精密管道:解析HTML建DOM → 解析CSS建CSSOM → 合并成渲染树 → 计算布局 → 逐层绘制 → GPU合成。
每一步都在优化性能、处理容错、平衡资源。你每天使用的这个工具,本身就是一个工程奇迹。