渲染流程:HTML、CSS和JavaScript,是如何变成页面的?

渲染流程

渲染流水线
按照渲染的时间顺序,流水线可分为如下几个子阶段:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。
开始每个子阶段都有其输入的内容
然后每个子阶段有其处理过程
最终每个子阶段会生成输出内容

构建 DOM 树

这是因为浏览器无法直接理解和使用 HTML,所以需要将HTML 转换为浏览器能够理解的结构——DOM 树。
树结构示意图

样式计算(Recalculate Style)

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

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

HTML加载CSS的三种方式
CSS 样式来源主要有三种:

  • 通过 link 引用的外部 CSS 文件
  • style标记内的 CSS
  • 元素的 style 属性内嵌的 CSS
    当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets。

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

属性值标准化:将所有值转换为渲染引擎容易理解的、标准化的计算值。

标准化属性值
从图中可以看到,2em 被解析成了 32px,red 被解析成了 rgb(255,0,0),bold 被解析成了 700……

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

涉及到 CSS 的继承规则和层叠规则
CSS 继承:就是每个 DOM 节点都包含有父节点的样式。

布局阶段

计算出 DOM 树中可见元素的几何位置,我们把这个计算过程叫做布局。

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

1.创建布局树

在这里插入图片描述
为了构建布局树,浏览器大体完成了下面这些工作:

  1. 遍历DOM树中的所有可见节点,并把这些节点加到布局中;
  2. 而不可见的节点会被布局树忽略掉,如head标签下面的全部内容,再比如body.p.span这个元素,因为它的属性包含display:none,所以这个元素也没有被包进布局树。

2.布局计算

在执行布局操作的时候,会把布局运算的结果重新写回布局树中,所以布局树既是输入内容也是输出内容,这是布局阶段一个不合理的地方,因为在布局阶段并没有清晰地将输入内容和输出内容区分开来。针对这个问题,Chrome 团队正在重构布局代码,下一代布局系统叫 LayoutNG,试图更清晰地分离输入和输出,从而让新设计的布局算法更加简单。

总结

渲染流水线图
渲染流程的前三个阶段:DOM生成样式计算布局。要点:

  1. 浏览器不能直接理解HTML数据,所以第一步需要将其转换为浏览器能够理解的DOM树结构;
  2. 生成DOM树后,还需要根据CSS样式表,来计算出DOM树所有节点的样式;
  3. 最后计算DOM元素的布局信息,使其都保存在布局树中。

分层

渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。
布局树和图层树关系示意图
并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。
单独的一个图层:

  1. 拥有层叠上下文属性的元素会被提升为单独的一层。
  2. 需要剪裁(clip)的地方也会被创建为图层。

图层绘制

渲染引擎会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表:
绘制列表

栅格化(raster)操作

绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。
在这里插入图片描述
在这里插入图片描述
从图中可以看出,渲染进程把生成图块的指令发送给 GPU,然后在 GPU 中执行生成图块的位图,并保存在 GPU 的内存中。

渲染流水线大总结

一个完整的渲染流程大致可总结为如下:

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

相关概念

1. 更新了元素的几何属性(重排)

更新元素的几何属性
通过 JavaScript 或者 CSS 修改元素的几何位置属性,例如改变元素的宽度、高度等,那么浏览器会触发重新布局,解析之后的一系列子阶段,这个过程就叫重排。无疑,重排需要更新完整的渲染流水线,所以开销也是最大的。

2.更新元素的绘制属性(重绘)

在这里插入图片描述
如果修改了元素的背景颜色,那么布局阶段将不会被执行,因为并没有引起几何位置的变换,所以就直接进入了绘制阶段,然后执行之后的一系列子阶段,这个过程就叫重绘。相较于重排操作,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。

3.直接合成阶段

更改一个既不要布局也不要绘制的属性,会发生什么变化呢?渲染引擎将跳过布局和绘制,只执行后续的合成操作,我们把这个过程叫做合成
在这里插入图片描述
我们使用了 CSS 的 transform 来实现动画效果,这可以避开重排和重绘阶段,直接在非主线程上执行合成动画操作。这样的效率是最高的,因为是在非主线程上合成,并没有占用主线程的资源,另外也避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值