渲染树构建、布局和绘制

Ilya Grigorik
Ilya Grigorik

CSSOM 树和 DOM 树会组合成渲染树,然后用于计算每个可见元素的布局,并作为绘制进程的输入,将像素渲染到屏幕上。优化上述每一个步骤对于实现最佳渲染性能至关重要。

在关于构建对象模型的上一部分中,我们根据 HTML 和 CSS 输入构建了 DOM 树和 CSSOM 树。不过,这两个对象都是独立的对象,分别捕获文档的不同方面:一个描述内容,另一个描述需要对文档应用的样式规则。我们该如何将两者合并,并让浏览器在屏幕上渲染像素呢?

摘要

  • DOM 树和 CSSOM 树会合并形成渲染树。
  • 渲染树仅包含渲染网页所需的节点。
  • 布局会计算每个对象的精确位置和大小。
  • 最后一步是绘制,它会采用最终的渲染树并将像素渲染到屏幕上。

首先,浏览器将 DOM 和 CSSOM 合并成一个“渲染树”,以捕获网页上所有可见的 DOM 内容,以及每个节点的所有 CSSOM 样式信息。

DOM 和 CSSOM 合并以创建渲染树

为了构建渲染树,浏览器大致会执行以下操作:

  1. 从 DOM 树的根部开始,遍历每个可见节点。

    • 某些节点不可见(例如,脚本标记、元标记等),因为它们不会反映在渲染的输出中,因此会被忽略。
    • 有些节点通过 CSS 隐藏,呈现树中也会省略;例如,呈现树中就缺少 span 节点,因为我们有一条明确的规则对其设置“display: none”属性。
  2. 对于每个可见节点,请查找与之匹配的 CSSOM 规则,然后应用这些规则。

  3. 发出可见节点及其内容及其计算样式。

最终输出是一个渲染树,其中包含屏幕上所有可见内容的内容和样式信息。有了渲染树,我们就可以进入“布局”阶段。

到目前为止,我们已计算了哪些节点应该可见以及它们经过计算的样式,但我们尚未计算它们在设备视口中的确切位置和大小,这就是“布局”阶段,也称为“自动重排”。

为了弄清每个对象在网页上的确切大小和位置,浏览器从渲染树的根节点开始进行遍历。我们来看一个简单的实践示例:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <title>Critial Path: Hello world!</title>
  </head>
  <body>
    <div style="width: 50%">
      <div style="width: 50%">Hello world!</div>
    </div>
  </body>
</html>

试试看

以上网页的正文包含两个嵌套 div:第一个(父)div 将节点的显示尺寸设置为视口宽度的 50%,第二个由父 div 包含的 div 将其宽度设置为其父项的 50%,即视口宽度的 25%。

计算布局信息

布局流程的输出是一个“盒模型”,它会精确捕获每个元素在视口中的确切位置和尺寸:所有相对测量值都将转换为屏幕上的绝对像素。

最后,既然我们已经知道哪些节点可见,以及它们的计算样式和几何图形,我们就可以将这些信息传递到最后一个阶段,即将渲染树中的每个节点转换为屏幕上的实际像素。此步骤通常称为“绘制”或“光栅化”。

此过程可能需要一些时间,因为浏览器必须完成大量工作。不过,通过 Chrome 开发者工具,您可以更深入地了解上述三个阶段。我们来看看初始“hello world”示例的布局阶段:

在开发者工具中测量布局

  • “Layout”事件会在时间轴中捕获渲染树构建、位置和大小计算。
  • 布局完成后,浏览器会发出“Paint Setup”和“Paint”事件,将渲染树转换成屏幕上的像素。

执行渲染树构建、布局和绘制所需的时间取决于文档的大小、应用的样式以及运行文档的设备:文档越大,浏览器的工作量就越大;样式越复杂,绘制所用的时间也就越长(例如,纯色的绘制“成本低”,而阴影的计算和渲染“成本高昂”)。

网页最终会显示在视口中:

已渲染的 Hello World 页面

下面简要概述了浏览器的操作步骤:

  1. 处理 HTML 标记并构建 DOM 树。
  2. 处理 CSS 标记并构建 CSSOM 树。
  3. 将 DOM 和 CSSOM 合并到呈现树中。
  4. 在渲染树上运行布局,以计算每个节点的几何图形。
  5. 将各个节点绘制到屏幕上。

我们的演示页面可能看起来很简单,但实际上需要完成大量工作。如果 DOM 或 CSSOM 被修改,您就必须重复上述过程,以便确定哪些像素需要在屏幕上重新渲染。

优化关键渲染路径是指最大限度减少执行上述第 1 步到第 5 步所花费的总时间的过程。这样做可以尽快将内容渲染到屏幕上,还可以缩短首次渲染后屏幕更新间隔的时间;也就是说,为互动式内容实现更高的刷新率。

反馈