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

构建 DOM 树

构建 DOM 树的输入内容是一个非常简单的 HTML 文件,然后经由HTML 解析器解析,最终输出树状结构的 DOM。
DOM 和 HTML 内容几乎是一样的,但是和 HTML 不同的是,DOM 是保存在内存中树状结构,可以通过 JavaScript 来查询或修改其内容。

样式计算(Recalculate Style)

样式计算的目的是为了计算出 DOM 节点中每个元素的具体样式

  1. 把 CSS 转换为浏览器能够理解的结构
    以当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets。
  2. 转换样式表中的属性值,使其标准化
    CSS 文本中有很多属性值,如 2em、blue、bold,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。2em 被解析成了 32px,red 被解析成了 rgb(255,0,0),bold 被解析成了 700……
  3. 计算出 DOM 树中每个节点的具体样式
    样式计算阶段的目的是为了计算出 DOM 节点中每个元素的具体样式,在计算过程中需要遵守 CSS 的继承和层叠两个规则。这个阶段最终输出的内容是每个 DOM 节点的样式,并被保存在 ComputedStyle 的结构内。
    CSS 继承就是每个 DOM 节点都包含有父节点的样式。
    层叠是 CSS 的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法。它在 CSS 处于核心地位,CSS 的全称“层叠样式表”正是强调了这一点。

布局阶段

  1. 创建布局树
    遍历 DOM 树中的所有可见节点,并把这些节点加到布局中;而不可见的节点会被布局树忽略掉,如 head 标签下面的全部内容,属性包含 dispaly:none的元素。
  2. 布局计算
    计算布局树节点的坐标位置,在执行布局操作的时候,会把布局运算的结果重新写回布局树中,所以布局树既是输入内容也是输出内容,这是布局阶段一个不合理的地方,因为在布局阶段并没有清晰地将输入内容和输出内容区分开来。

分层

因为页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-indexing做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)。
浏览器的页面实际上被分成了很多图层,这些图层叠加后合成了最终的页面。
通常情况下,并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。

  1. 拥有层叠上下文属性的元素会被提升为单独的一层。明确定位属性的元素、定义透明属性的元素、使用 CSS 滤镜的元素等,都拥有层叠上下文属性。
  2. 需要剪裁(clip)的地方也会被创建为图层。内容超过容器的尺寸时,这时候就产生了剪裁,渲染引擎会把裁剪文字内容的一部分用于显示在 div 区域,出现这种裁剪情况的时候,渲染引擎会为文字部分单独创建一个层,如果出现滚动条,滚动条也会被提升为单独的层。

图层绘制

在完成图层树的构建之后,渲染引擎会对图层树中的每个图层进行绘制。渲染引擎会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表。

栅格化(raster)操作

绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给合成线程。
合成线程会将图层划分为图块(tile),这些图块的大小通常是 256x256或者 512x512。
然后合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。

合成和显示

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

你可能感兴趣的:(渲染流程:HTML、CSS和JavaScript,是如何变成页面的?)