浏览器渲染原理

245 阅读4分钟

浏览器渲染原理

首先整体介绍一下浏览器的渲染过程

  1. 根据 HTML 文件以及 CSS 文件构建 DOM 树和 CSSOM 树
  2. 将两棵树合成一棵渲染树(Render Tree)
  3. 根据渲染树来布局,以计算每个节点的几何信息
  4. Paint 绘制
  5. Compose 合成

DOM树构建流程

  1. 转换: 浏览器从磁盘或网络读取 HTML 的原始字节,并根据文件的指定编码(例如 UTF-8)将它们转换成各个字符。
  2. 令牌化: 浏览器将字符串转换成 W3C HTML5 标准规定的各种令牌,例如,“”、“”,以及其他尖括号内的字符串。每个令牌都具有特殊含义和一组规则。
  3. 词法分析: 发出的令牌转换成定义其属性和规则的“对象”。
  4. DOM 构建: 最后,由于 HTML 标记定义不同标记之间的关系(一些标记包含在其他标记内),创建的对象链接在一个树数据结构内,此结构也会捕获原始标记中定义的父项-子项关系:HTML 对象是 body 对象的父项,body 是 paragraph 对象的父项,依此类推。

整个流程的最终输出是我们这个简单页面的文档对象模型 (DOM),浏览器对页面进行的所有进一步处理都会用到它。如下图所示。

CSSOM树构建流程

CSSOM 树的构建流程跟上面所说的 DOM 树的构建流程基本一模一样,也会经历上面的四个过程,把收到的 CSS 规则转换成某种浏览器能够理解和处理的东西。

CSSOM 为何具有树结构?为页面上的任何对象计算最后一组样式时,浏览器都会先从适用于该节点的最通用规则开始(例如,如果该节点是 body 元素的子项,则应用所有 body 样式),然后通过应用更具体的规则(即规则“向下级联”)以递归方式优化计算的样式。

合成渲染树

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

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

为构建渲染树,浏览器大体上完成了下列工作:

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

    • 某些节点不可见(例如脚本标记、元标记等),因为它们不会体现在渲染输出中,所以会被忽略。
    • 某些节点通过 CSS 隐藏,因此在渲染树中也会被忽略,例如,上例中的 span 节点---不会出现在渲染树中,---因为有一个显式规则在该节点上设置了“display: none”属性。
  2. 对于每个可见节点,为其找到适配的 CSSOM 规则并应用它们。

  3. 发射可见节点,连同其内容和计算的样式。

简单提一句,请注意 visibility: hidden 与 display: none 是不一样的。前者隐藏元素,但元素仍占据着布局空间(即将其渲染成一个空框),而后者 (display: none) 将元素从渲染树中完全移除,元素既不可见,也不是布局的组成部分。

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

布局

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

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

绘制

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