说明
浏览器工作原理与实践专栏学习笔记
准备工作
渲染流程示意图
下图的 HTML、CSS、JavaScript 数据,这些数据经过
中间渲染模块
的处理,最终输出为屏幕上的像素。
渲染流水线示意图
由于渲染机制过于复杂,所以渲染模块在执行过程中会被划分为很多子阶段,输入的 HTML 经过这些子阶段,最后输出像素。我们把这样的一个处理流程叫做渲染流水线
。
按照渲染的时间顺序,流水线可分为如下几个子阶段:
- 1、构建 DOM 树
- 2、样式计算
- 3、布局阶段
- 4、分层
- 5、绘制
- 6、分块
- 7、光栅化
- 8、合成
需要重点关注:
- 开始每个子阶段都有其输入的内容;
- 然后每个子阶段有其处理过程;
- 最终每个子阶段会生成输出内容。
1、构建 DOM 树
为什么要构建 DOM 树呢?
这是因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。
什么是树结构?
图中每个点我们称为节点
,相连的节点称为父子节点
。
DOM 树构建过程
构建 DOM 树的输入内容是一个非常简单的 HTML 文件,然后经由 HTML 解析器解析,最终输出树状结构的 DOM。
DOM 可视化
为了更加直观地理解 DOM 树,我们在控制台里面输入“document”后回车,这样你就能看到一个完整的 DOM 树结构,如下图所示:
DOM 和 HTML 内容几乎是一样的,但是和 HTML 不同的是,DOM 是保存在内存中树状结构,可以通过 JavaScript 来查询或修改其内容。
通过 JavaScript 修改 DOM
在控制台中输入:
document.getElementsByTagName("p")[0].innerText = "black";
现在已经生成 DOM 树了,但是 DOM 节点的样式依然不知道,要让 DOM 节点拥有正确的样式,这就需要样式计算。
2、样式计算(Recalculate Style)
样式计算的目的是为了计算出 DOM 节点中每个元素的具体样式。
大体可分为三步来完成:
2.1、把 CSS 转换为浏览器能够理解的结构
HTML 加载 CSS 的三种方式:
和 HTML 文件一样,浏览器也是无法直接理解这些纯文本的 CSS 样式,当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets。
我们可以在控制台输入:
document.styleSheets
渲染引擎会把获取到的 CSS 文本全部转换为 styleSheets 结构中的数据,并且该结构同时具备了查询和修改
功能,这会为后面的样式操作提供基础。
2.2、转换样式表中的属性值,使其标准化
什么是属性值标准化?
我们先看下面的一段样式:
body { font-size: 2em } p {color:blue;} span {display: none} div {font-weight: bold} div p {color:green;} div {color:red; }
CSS 文本中有很多属性值,如 2em、blue、bold,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。
标准化属性值
2.3、计算出 DOM 树中每个节点的具体样式
计算离不开CSS 的继承规则和层叠规则
2.3.1、CSS 继承就是每个 DOM 节点都包含有父节点的样式。
例子:样式表最终应用到 DOM 节点的效果
body { font-size: 20px } p {color:blue;} span {display: none} div {font-weight: bold;color:red} div p {color:green;}
计算后 DOM 的样式
样式的继承过程界面
2.3.2、层叠是 CSS 的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法。它在 CSS 处于核心地位,CSS 的全称“层叠样式表”正是强调了这一点。
样式计算阶段的目的是为了计算出 DOM 节点中每个元素的具体样式,在计算过程中需要遵守 CSS 的继承和层叠两个规则。这个阶段最终输出的内容是每个 DOM 节点的样式,并被保存在 ComputedStyle 的结构内。
DOM 元素最终计算的样式
3、布局阶段
计算出 DOM 树中可见元素的几何位置,我们把这个计算过程叫做布局。
Chrome 在布局阶段需要完成两个任务:创建布局树和布局计算。
3.1、创建布局树
DOM 树还含有很多不可见的元素,比如 head 标签,还有使用了 display:none
属性的元素。在显示之前,还要额外地构建一棵只包含可见元素布局树
。
布局树的构造过程:DOM 树中所有不可见的节点都没有包含到布局树中。
- 遍历 DOM 树中的所有可见节点,并把这些节点加到布局树中;
- 而不可见的节点会被布局树忽略
3.2、布局计算
在执行布局操作的时候,会把布局运算的结果重新写回布局树中,所以布局树既是输入内容也是输出内容,这是布局阶段一个不合理的地方。
因为在布局阶段并没有清晰地将输入内容和输出内容区分开来。
针对这个问题,Chrome 团队正在重构布局代码,下一代布局系统叫 LayoutNG,试图更清晰地分离输入和输出,从而让新设计的布局算法更加简单。