浏览器渲染流程

由于渲染机制过于复杂,所以渲染模块在执行过程中会被划分为很多子阶段,输入的 HTML 经过这些子阶段,最后输出像素。我们把这样的一个处理流程叫做渲染流水线,其大致流程如下图所示:

Image.png

🐼按照渲染的时间顺序,流水线可分为如下几个子阶段:

  1. 构建 DOM 树
  2. 样式计算
  3. 布局阶段
  4. 分层
  5. 绘制
  6. 分块
  7. 光栅化
  8. 合成。

我们可以把渲染流水线当作一个车间流水线,我们只关注输入输出,中间的处理当作黑盒即可;不去关注过程

构建 DOM 树

由于浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。

Image [2].png

HTML解析器:接收到HTML字节流时,首先要经过渲染引擎的HTML解析器,将HTML字节流转换成DOM树结构。

构建 DOM 树的输入内容是一个非常简单的 HTML 文件,然后经由 HTML 解析器解析,最终输出树状结构的 DOM。

可以看到,DOM 和 HTML 内容几乎是一样的,但是和 HTML 不同的是,DOM 是保存在内存中树状结构,可以通过 JavaScript 来查询或修改其内容。

样式计算(Recalculate Style)

已经生成 DOM 树了,但是 DOM 节点的样式我们依然不知道,要让 DOM 节点拥有正确的样式,这就需要样式计算了。

样式计算的目的是为了计算出 DOM 节点中每个元素的具体样式,这个阶段大体可分为三步来完成。

1. 把 CSS 转换为浏览器能够理解的结构

和 HTML 文件一样,浏览器也是无法直接理解这些纯文本的 CSS 样式,所以当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets

在控制台中输入 document.styleSheets,然后就看到如下图所示的结构:

Image [3].png

渲染引擎会把获取到的 CSS 文本全部转换为 styleSheets 结构中的数据,并且该结构同时具备了查询修改功能,这会为后面的样式操作提供基础。

2. 转换样式表中的属性值,使其标准化

将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。

Image [4].png

3. 计算出 DOM 树中每个节点的具体样式

样式计算阶段的目的是为了计算出 DOM 节点中每个元素的具体样式,在计算过程中需要遵守 CSS 的继承层叠两个规则。这个阶段最终输出的内容是每个 DOM 节点的样式,并被保存在 ComputedStyle 的结构内

📚CSS 继承

CSS 继承就是每个 DOM 节点都包含有父节点的样式。

📒层叠

层叠是 CSS 的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法。它在 CSS 处于核心地位,CSS 的全称“层叠样式表”正是强调了这一点

布局阶段

因为我们还不知道 DOM 元素的几何位置信息。那么接下来就需要计算出 DOM 树中可见元素的几何位置,我们把这个计算过程叫做布局

Chrome 在布局阶段需要完成两个任务:创建布局树布局计算

1. 创建布局树

  • 遍历 DOM 树中的所有可见节点,并把这些节点加到布局树中;
  • 而不可见的节点会被布局树忽略掉,因为它的属性包含 dispaly:none,所以这个元素也没有被包进布局树。

2. 布局计算

当Webkit创建RenderObject对象之后,每个对象是不知道自己的位置,大小等信息的,WebKit根据盒子模型来计算他的位置,大小等信息,这个过程就是布局计算

布局计算是一个复杂的过程,我简单的可以总结为:界面是由很多很多的框模型组成的,每个框模型是由元素的类型以及display属性决定的。而不同的Box会参与到不同的格式上下文中(Formatting Context),完成布局的计算。

分层

页面是个二维平面,但是层叠上下文能够让 HTML 元素具有三维概念,这些 HTML 元素按照自身属性的优先级分布在垂直于这个二维平面的 z 轴上。

Image [5].png

页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-inde 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。

Image [6].png

图层绘制

在完成图层树的构建之后,渲染引擎会对图层树中的每个图层进行绘制;

渲染引擎实现图层的绘制与之类似,会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表,如下图所示

Image [7].png

栅格化(raster)操作

绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。

Image [8].png

合成和显示

一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。

总结

Image [9].png

  1. 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
  2. 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
  3. 创建布局树,并计算元素的布局信息。
  4. 对布局树进行分层,并生成分层树。
  5. 为每个图层生成绘制列表,并将其提交到合成线程。
  6. 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
  7. 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
  8. 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。
Kommentare

:D 一言句子获取中...