发布时间:2014 年 3 月 31 日
浏览器要渲染网页,需要先构建 DOM 并 CSSOM 树。因此,我们需要确保同时提供 HTML 和 尽快将 CSS 推送到浏览器。
摘要
- 字节 → 字符 → 令牌 → 节点 → 对象模型。
- 将 HTML 标记转换为文档对象模型 (DOM);CSS 标记是 转换为 CSS 对象模型 (CSSOM)。
- DOM 和 CSSOM 是独立的数据结构。
- Chrome DevTools 的“Performance”面板可让我们捕获和检查 DOM 和 CSSOM 的构建和处理开销。
文档对象模型 (DOM)
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="style.css" rel="stylesheet" />
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg" /></div>
</body>
</html>
让我们从可能的最简单情况入手:一个包含一些文本和一幅图片的普通 HTML 页面。浏览器如何处理此页面?
- 转换:浏览器从磁盘或网络读取 HTML 的原始字节,并根据文件的指定编码(例如 UTF-8)将它们转换成各个字符。
- 令牌化:浏览器将字符串转换为不同的
令牌 - 按照 W3C HTML5 标准规定
(例如
<html>
、<body>
)以及 尖括号。每个词元都有特殊的含义和一套规则。 - 词法分析:发出的令牌转换成定义其属性和规则的“对象”。
- DOM 构建:最后,由于 HTML 标记定义了不同标记之间的关系(某些标记包含在其他标记中),因此创建的对象会以树状数据结构的形式关联起来,该数据结构还会捕获原始标记中定义的父子关系:HTML 对象是 body 对象的父级,body 是 paragraph 对象的父级,以此类推,直到构建文档的完整表示。
整个流程的最终输出是我们这个简单页面的文档对象模型 (DOM),浏览器对页面进行的所有进一步处理都会用到它。
浏览器每次处理 HTML 标记时,都会完成之前定义的所有步骤:将字节转换成字符,确定令牌,将令牌转换成节点,然后构建 DOM 树。整个过程可能需要一些时间 特别是在需要处理大量 HTML 的情况下。
如果您打开 Chrome 开发者工具并在网页加载时记录时间轴, 您可以看到完成该步骤实际所花的时间。在上一个示例中, 将一段 HTML 代码转换成 DOM 树大约需要 5 毫秒。对于 页面较大,此过程可能需要更长的时间。创建 如果浏览器必须加载流畅的动画 处理大量 HTML。
DOM 树捕获文档标记的属性和关系, 但它并不能说明该元素在呈现时的外观这就是 CSSOM 的责任。
CSS 对象模型 (CSSOM)
浏览器在构建基本页面的 DOM 时,
文档 <head>
中的 <link>
元素,引用外部 CSS
样式表:style.css
。预测到它需要该资源来渲染
它会立即发出对该资源的请求
包含以下内容:
body {
font-size: 16px;
}
p {
font-weight: bold;
}
span {
color: red;
}
p span {
display: none;
}
img {
float: right;
}
我们本来可以直接在 HTML 标记内声明样式(内嵌),但是 通过保持 CSS 独立于 HTML,我们可以将内容和设计视为 分别是:设计人员可以专注于 CSS,开发者可以专注于 HTML,因为 和其他顾虑
与处理 HTML 时一样,我们需要将收到的 CSS 规则转换成某种浏览器能够理解和处理的东西。因此,我们重复 HTML 过程, 但对于 CSS 而不是 HTML:
CSS 字节转换成字符,接着转换成令牌和节点,最后链接到一个称为“CSS 对象模型”(CSSOM) 的树结构内:
CSSOM 为何具有树结构?在计算 那么浏览器首先会选择最宽泛的 规则适用于该节点(例如,如果它是 body 元素的子元素, 则应用所有正文样式),然后以递归方式优化计算的样式 应用更具体的规则也就是说,规则会“向下级联”。
以上面介绍的 CSSOM 树为例进行更具体的阐述。<span>
标记内包含的任何置于 body 元素内的文本都将具有 16 像素字号,并且颜色为红色 - font-size
指令从 body
向下级联至 span
。不过,如果 span
是
paragraph (p
) 标记,则其内容不会显示。
另请注意,前面描述的树并非完整的 CSSOM 树, 仅显示我们决定在样式表中替换的样式。所有浏览器 提供了一组默认的样式,也称为“用户代理样式”, 在不提供任何自定义值时看到的结果 - 我们的样式会覆盖这些 默认值。
如需了解 CSS 处理所需的时间,您可以在 DevTools 中记录时间线并查找“Recalculate Style”事件:与 DOM 解析不同,该时间线不显示单独的“Parse CSS”条目,而是在这一个事件下一同捕获解析和 CSSOM 树构建,以及计算的样式的递归计算。
我们的小样式表需要大约 0.6 毫秒的处理时间,影响页面上的 8 个元素 - 虽然不多,但同样会产生开销。然而,在哪里 这八个元素来自哪里?CSSOM 和 DOM 是独立的数据结构! 结果证明,浏览器隐藏了一个重要步骤。接下来,我们将介绍将 DOM 和 CSSOM 链接起来的渲染树。