发布时间: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 DevTools 并在加载页面时记录时间轴,您可以看到执行此步骤的实际时间 - 在前面的示例中,我们将一块 HTML 转换为 DOM 树花费了大约 5 毫秒。对于较大的页面,此过程可能需要更长的时间。在创建平滑动画时,如果浏览器必须处理大量 HTML,这可能会成为瓶颈。
DOM 树捕获文档标记的属性和关系,但它没有告诉我们元素在渲染时的外观。这是 CSSOM 的责任。
CSS 对象模型 (CSSOM)
当浏览器构建基本页面的 DOM 时,它在文档的 <head>
中遇到了引用外部 CSS 样式表的 <link>
元素: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 元素的子元素,则应用所有 body 样式),然后通过应用更具体的规则来递归地优化计算出的样式;也就是说,规则“级联下降”。
为了使其更具体,请考虑先前描述的 CSSOM 树。包含在 body 元素内的 <span>
标签中的任何文本,字体大小均为 16 像素,文本为红色 - font-size
指令从 body
级联到 span
。但是,如果 span
是段落 (p
) 标签的子标签,则不会显示其内容。
另请注意,先前描述的树不是完整的 CSSOM 树,仅显示了我们决定在样式表中覆盖的样式。每个浏览器都提供一组默认样式,也称为“用户代理样式” - 这就是我们在不提供任何自己的样式时看到的内容 - 我们的样式会覆盖这些默认值。
要了解 CSS 处理需要多长时间,您可以在 DevTools 中记录时间轴并查找“重新计算样式”事件:与 DOM 解析不同,时间轴不显示单独的“解析 CSS”条目,而是捕获解析和 CSSOM 树构建,以及在此事件下计算出的样式的递归计算。
我们微不足道的样式表需要大约 0.6 毫秒才能处理,并影响页面上的八个元素 - 不多,但再次强调,并非免费。但是,这八个元素来自哪里?CSSOM 和 DOM 是独立的数据结构!事实证明,浏览器隐藏了一个重要步骤。接下来,将介绍 渲染树,它将 DOM 和 CSSOM 链接在一起。