浏览器渲染原理

Wed, November 6, 2024 - 7 min read

一 什么是渲染

将 HTML 字符串通过一连串的规则得到像素信息。

二 渲染流水线

整体框架:

Browser Image

2.0 渲染时间点

当浏览器的网络线程收到 HTML 文档后,会产生一个渲染任务,并将其传递给渲染主线程的消息队列。

在[[事件循环]]机制的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程。

Browser Image

2.1 解析 HTML - Parse HTML

将 HTML 进行解析,生成 DOM 树、CSSOM 树。

2.1.1 解析 HTML 生成 DOM 树

Browser Image

从上到下解析 HTML 文档,遇到 CSS 解析 CSS,遇到 JS 根据规则执行 JS。

2.1.2 解析 CSS 生成 CSSOM 树

Browser Image

StyleSheetList 存储当前页面所有样式表的集合,样式表分为:

  1. <Style> 内部样式表
  2. <Link ...> 外部样式表
  3. <div style="..." 行内样式表
  4. 浏览器默认样式表

2.1.3 重要细节

1️⃣HTML 解析过程中遇到 CSS 代码怎么办?

为了提高解析效率,浏览器会启动一个预下载线程,快速浏览,预解析 CSS。CSSOM 的生成还是需要依靠渲染主线程。

Browser Image

如果主线程解析到 Link 位置,此时外部的 CSS 还没有下载、预解析好,主线程不会等待,继续解析后续的 HTML。因为下载和预解析 CSS 的工作是在预下载线程进行的,不会阻塞 HTML 解析。

2️⃣HTML 解析过程中遇到 JS 代码怎么办?

判断 <script>的属性中是否包含asyncdefer,根据不同的规则进行解析:

Browser Image

如果没有以上两个属性,渲染主线程解析 HTML 时遇到 JS 则会阻塞,必须暂停⼀切⾏为,等待下载并执⾏完脚本后才能继续解析 HTML。

JS 代码的执行过程可能会修改当前的 DOM 树,所以 DOM 树会暂停。

Browser Image

2.2 样式计算 - Recalculate Style

将 DOM 树和 CSSOM 树进行样式计算,得到每个节点最终的计算样式,生成一颗带样式的 DOM 树,即渲染树

主线程会遍历得到的 DOM 树,依次为树中的每个节点计算出它最终的样式。

在这一过程中,预设值会变成绝对值,比如 red 会变成 rgb(255, 0, 0);相对单位会变成绝对单位,比如 em 会变成 px

并且一些节点会被忽略。如一些节点会使用 CSS(例如 display: "none" 属性)隐藏,它们将被忽略。 如 scriptmeta 标签不可见(这些标签在浏览器默认样式表中为display: "none"),会被忽略。

Browser Image

2.3 布局/重排 - Layout

渲染树保存有关哪些节点显示以及它们计算出的样式的信息,但不包括每个节点的尺寸或位置。

在布局阶段,基于渲染树,计算这些节点在设备视口的确切位置及其大小,例如节点的宽高、相对包含快的位置。

Browser Image

布局或回流(reflow)并非仅发生一次,而是每当我们在 DOM 中更改影响页面布局(即使是部分影响)的任何内容时都会发生。元素位置被重新计算的情况示例有:

  • 向 DOM 中添加或删除元素
  • 调整浏览器窗口大小
  • 更改元素的宽度、位置或使其浮动

2.4 分层 - Layer

主线程会使用一套策略对整个布局树进行分层。

分层的好处在于,将来某一个层改变后,仅会对该层进行后续处理,从而提升效率。

如果我们想要暗示浏览器某些元素应该位于单独的层上,我们可以使用 will-change CSS 属性。有一些特定的属性和元素表示创建了一个新层。其中一些是 <video> 、 <canvas> 、 opacity CSS 属性、一个 3D transform 、 will-change 等等。这些节点及其后代将绘制到它们自己的层上。

Browser Image

2.5 绘制/重绘 - Paint

为每一层生成如何绘制的指令。

Browser Image 渲染主线程的工作到此为止,剩余步骤交给其他线程完成。

Browser Image

2.6 分块 - Tiling

分块将每一层分为多个小的区域。

Browser Image

分块的⼯作是交给多个线程同时进⾏的。

Browser Image

2.7 光栅化 - Raster

光栅化是将每个块变成位图,优先处理靠近视口的块。

Browser Image

此过程会用到 GPU 加速:

Browser Image

2.8 画 - Draw

合成线程计算出每个位图在屏幕上的位置,交给 GPU 进⾏最终呈现。

完整流程:

Browser Image

三 常见面试题

3.1 什么是 Reflow?

Reflow 的本质就是重新计算 Layout 树。

当做出一些操作,影响页面几何布局,引发一系列的重新计算:CSSOM 树改变,Render 树更新,Layout 树更新,重新绘制。

Browser Image

3.2 什么是 Repaint?

Repaint 的本质就是重新根据分层信息,计算新的绘制指令,进行绘制。

当改动了可见样式后,就需要重新计算,会引发重绘。

Browser Image

3.3 为什么 transform 效率高?

因为 transform 既不影响布局也不影响绘制,它影响的只是渲染流程的最后一个「draw」阶段(和 animation 配合使用)。

由于 draw 阶段在合成线程中,所以 tranform 的变化几乎不会影响渲染主线程。反之,渲染主线程如何阻塞,也不会影响 transform 的变化。

Browser Image

Browser Image