HTML、CSS 和 JavaScript 是如何变成页面的?

HTML、CSS 和 JavaScript 是如何变成页面的?

前言

在前面的一篇文章中 从输入 URL 到页面显示,这中间发生了什么?,笔者介绍了从输入 URL 到页面显示的大致过程,在介绍浏览器的渲染阶段时介绍得不够详细,这篇文章将比较详细地介绍这一过程,以及这一过程中重排、重绘以及合成的概念。

渲染流程

1. 构建 DOM 树

为什么要构建 DOM 树呢?是因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树

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

document.getElementsByTagName("p")[0].innerText = "black";

2. 样式计算

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

CSS 样式来源主要有三种:

  1. 通过 link 引用的外部 CSS 文件

  2. <style> 标记内的 CSS

  3. 元素的 style 属性内嵌的 CSS(内联样式)

当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets

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

如 2em、blue、bold,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化

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

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

3. 布局阶段

创建布局树

遍历 DOM 树中的所有可见节点,并把这些节点加到布局树中,而不可见的节点会被布局树忽略掉。

布局计算

最后计算 DOM 元素的布局信息,使其都保存在布局树中

4. 分层

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

浏览器的页面实际上被分成了很多图层,这些图层叠加后合成了最终的页面。

那么需要满足什么条件,渲染引擎才会为特定的节点创建新的图层呢?

  • 拥有层叠上下文属性的元素会被提升为单独的一层,如明确定位属性的元素、定义透明属性的元素、使用 CSS 滤镜的元素等

  • 需要剪裁(clip)的地方也会被创建为图层

如文字所显示的区域肯定会超出了规定的范围,这时候就产生了剪裁,渲染引擎会把裁剪文字内容的一部分用于显示在 div 区域。出现这种裁剪情况的时候,渲染引擎会为文字部分单独创建一个层,如果出现滚动条,滚动条也会被提升为单独的层。

5. 图层绘制

渲染引擎会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表。绘制列表 只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。

6. 栅格化(raster)操作

合成线程会将图层划分为 图块(tile)。然后合成线程会按照视口附近的图块来优先生成 位图,实际生成位图的操作是由 栅格化 来执行的。所谓栅格化,是指将图块转换为位图。而图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的。

通常,栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫 快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。

7. 合成和显示

一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。

浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。

相关概念:

重排

HTML、CSS 和 JavaScript 是如何变成页面的?

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

重绘

HTML、CSS 和 JavaScript 是如何变成页面的?

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

合成

HTML、CSS 和 JavaScript 是如何变成页面的?

在上图中,如果你更改一个既不要布局也不要绘制的属性,渲染引擎将跳过布局和绘制,只执行后续的合成操作,我们把这个过程叫做 合成

使用 CSS 的 transform 来实现动画效果,可以避开重排和重绘阶段,直接在非主线程上执行合成动画操作。这样的效率是最高的,因为是在非主线程上合成,并没有占用主线程的资源,另外也避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率。

文章出自:https://juejin.cn/post/7221138459813445688

作者:codinglin


原文始发于微信公众号(前端24):HTML、CSS 和 JavaScript 是如何变成页面的?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/216288.html

(0)
李, 若俞的头像李, 若俞

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!