DOM 树、CSSOM 树和 渲染树 (Render Tree) 的关系是什么?
这是一个非常经典的前端面试题,也是理解浏览器渲染原理(Critical Rendering Path,关键渲染路径)的核心。
简单来说,它们的关系可以用一个公式概括:
以下是详细的深度解析:
1. 三者的定义与角色
DOM 树 (Document Object Model Tree)
- 来源:HTML 文档。
- 作用:表示页面的内容(Content)和结构。
- 包含:所有的 HTML 标签(
<div>,<p>,<span>等),包括<head>,<script>,<meta>以及被 CSS 隐藏的元素。 - 本质:它是完全基于 HTML 标签的父子层级关系构建的。
CSSOM 树 (CSS Object Model Tree)
- 来源:CSS 样式表(外部 .css 文件、
<style>标签、内联样式)。 - 作用:表示页面的样式规则(Styling)。
- 包含:所有的样式信息(颜色、尺寸、字体、显示模式等)。
- 本质:它不仅包含显式定义的样式,还包含浏览器默认样式(User Agent Styles)以及继承下来的样式。
渲染树 (Render Tree)
- 来源:DOM 树与 CSSOM 树的结合。
- 作用:表示页面上所有可见的内容及其样式。它是浏览器进行“布局(Layout)”和“绘制(Paint)”的依据。
- 包含:只有可见的节点。
- 本质:它是可视化的 DOM,每个节点被称为“渲染对象(Render Object)”或“渲染器(Renderer)”。
2. 它们是如何构建渲染树的?(核心关系)
浏览器构建渲染树的过程并不是简单地把 DOM 和 CSSOM 合并,而是一个筛选和匹配的过程:
- 遍历 DOM:浏览器从 DOM 树的根节点(通常是
<html>)开始遍历。 - 忽略不可见节点:
- 浏览器会忽略那些不需要渲染的节点(例如
<head>,<meta>,<script>,<link>)。 - 浏览器会查找 CSSOM,如果某个 DOM 节点被设置了
display: none,它不会被添加到渲染树中。
- 浏览器会忽略那些不需要渲染的节点(例如
- 匹配样式:对于每一个可见的 DOM 节点,浏览器会在 CSSOM 树中找到对应的样式规则并应用。
- 生成渲染树节点:结合了内容(DOM)和样式(CSSOM)的节点被插入到渲染树中。
3. 关键区别:DOM 树 vs 渲染树
这是理解它们关系中最容易混淆,也是最重要的部分:
| 特性 | DOM 树 | 渲染树 (Render Tree) | 备注 |
|---|---|---|---|
包含 <head> |
✅ 包含 | ❌ 不包含 | <head> 里的东西通常不可见 |
包含 display: none |
✅ 包含 | ❌ 不包含 | 这是最大的区别 |
包含 visibility: hidden |
✅ 包含 | ✅ 包含 | 虽然看不见,但占据空间,所以需要渲染 |
包含 伪元素 (::before) |
❌ 不包含 | ✅ 包含 | 伪元素不在 DOM 中,但在视觉上存在 |
| 节点对应关系 | 1:1 对应 HTML 标签 | 不一定 | 某些复杂结构(如 select)可能对应多个渲染对象 |
举个栗子:
HTML:
html
<div>
<p>Hello</p>
<span style="display: none;">Hidden Text</span>
<span style="visibility: hidden;">Invisible Text</span>
</div>
CSS:
css
div::after { content: "World"; }
- DOM 树:包含
div,p, 两个span。 - 渲染树:
- 包含
div。 - 包含
p(内容 "Hello")。 - 不包含 第一个
span(因为它display: none)。 - 包含 第二个
span(因为它visibility: hidden,虽然看不见但占位置,影响布局)。 - 包含
::after伪元素 (内容 "World",虽然它不在 DOM 里)。
- 包含
4. 渲染流程中的位置
为了理解它们的关系,我们需要看完整的渲染管线:
- Parsing HTML 构建 DOM 树。
- Parsing CSS 构建 CSSOM 树。
- Attachment DOM + CSSOM 合并生成 渲染树 (Render Tree)。
- Layout (Reflow) 根据渲染树,计算每个节点在屏幕上的确切坐标和大小。
- Paint 根据计算好的位置和样式,将像素绘制到屏幕上。
5. 总结与比喻
如果把网页比作盖房子:
- DOM 树 是 房屋的结构蓝图(这里是墙,那里是窗,这里是门)。
- CSSOM 树 是 装修设计单(墙刷成白色,窗户宽1米,门是木质的)。
- 渲染树 是 最终看到的房子实体。
- 如果蓝图里有个地下室,但装修单上写着“封死入口,不可见”(
display: none),那么在最终的实体(渲染树)里,你是进不去也看不到这个地下室的。 - 如果装修单上要求加一个装饰性的假梁(
::before),虽然结构蓝图里没有,但实体房子里会有。
- 如果蓝图里有个地下室,但装修单上写着“封死入口,不可见”(
一句话总结:
渲染树是 DOM 树和 CSSOM 树的视觉产物,它只包含需要显示在屏幕上的节点及其样式信息,是浏览器进行布局和绘制的直接依据。