渲染流程,代码是如何变为页面的(一)

作为前端工程师,通常,我们编写好HTML、CSS、JavaScript等文件,经过浏览器就会显示出漂亮的页面,但是发生了哪些事情,我们并不是很清楚。

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

image.png

按照渲染的时间顺序,流水线可分为如下几个子阶段:构建DOM树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。有三点内容是必须要清楚的:

  • 开始每个子阶段都有其输入的内容;
  • 然后每个子阶段有其处理过程;
  • 最终每个子阶段会生成输出内容。

构建DOM树

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

image.png

树这种结构非常像我们现实生活中的“树”,其中每个点称为节点,相连的节点称为父子节点。树结构在浏览器中的应用还是比较多的,渲染流程会频繁地使用树结构。

DOM树的构建过程,见下图:

image.png

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

为了更加直观地理解DOM树,可以打开Chrome的“开发者工具”,选择“Console”标签来打开控制台,然后在控制台里面输入“document”后回车,就能看到一个完整的DOM树结构,如下图所示:

image.png

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

那下面就来看看如何通过JavaScript来修改DOM的内容,在控制台中输入:

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

这行代码的作用是把第一个

标签的内容修改为black,具体执行结果可以参考下图:

image.png

在执行了一段修改第一个

标签的JavaScript代码后,DOM的第一个p节点的内容成功被修改,同时页面中的内容也被修改了,现在已经生成DOM树了,但是DOM节点的样式依然不知道,要让DOM节点拥有正确的样式,这就需要样式计算了。

样式计算

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

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

那CSS样式的来源主要有哪些呢?先参考下图:

image.png

从图中可以看出,CSS样式来源主要有三种:

  • 通过link引用的外部CSS文件
  • style标记内的 CSS
  • 元素的style属性内嵌的CSS

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

可以在Chrome控制台中查看其结构,只需要在控制台中输入document.styleSheets,就看到如下图所示的结构

image.png

从图中可以看出,这个样式表包含了很多种样式,已经把那三种来源的样式都包含进去了。我们需要知道渲染引擎会把获取到的CSS文本全部转换为styleSheets结构中的数据,并且该结构同时具备了查询和修改功能。

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

现在已经把现有的CSS文本转化为浏览器可以理解的结构了,那么接下来就要对其进行属性值的标准化操作。

要理解什么是属性值标准化,可以看下面这样一段CSS文本

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,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。

那标准化后的属性值是什么样子的?

image.png

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

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

现在样式的属性已被标准化了,接下来就需要计算DOM树中每个节点的样式属性了,如何计算呢?

这就涉及到CSS的继承规则和层叠规则了。

首先是CSS继承。CSS继承就是每个DOM节点都包含有父节点的样式。这么说可能有点抽象,我们可以结合具体例子,看下面这样一张样式表是如何应用到DOM节点上的。

body { font-size: 20px }
p {color:blue;}
span  {display: none}
div {font-weight: bold;color:red}
div  p {color:green;}

这张样式表最终应用到DOM节点的效果如下图所示:

image.png

从图中可以看出,所有子节点都继承了父节点样式。比如body节点的font-size属性是20,那body节点下面的所有节点的font-size都等于20。

为了加深对CSS继承的理解,可以打开Chrome的“开发者工具”,选择第一个“element”标签,再选择“style”子标签,会看到如下界面

image.png

这个界面展示的信息很丰富,大致可描述为如下

  1. 首先,可以选择要查看的元素的样式(位于图中的区域2中),在图中的第1个区域中点击对应的元素元素,就可以了下面的区域查看该元素的样式了。比如这里选择的元素是

    标签,位于html.body.div.这个路径下面

  2. 其次,可以从样式来源(位于图中的区域3中)中查看样式的具体来源信息,看看是来源于样式文件,还是来源于UserAgent样式表。这里需要特别提下UserAgent样式,它是浏览器提供的一组默认样式,如果不提供任何样式,默认使用的就是UserAgent样式。
  3. 最后,可以通过区域2和区域3来查看样式继承的具体过程。

以上就是CSS继承的一些特性,样式计算过程中,会根据DOM节点的继承关系来合理计算节点样式。

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

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

如果想了解每个DOM元素最终的计算样式,可以打开Chrome的“开发者工具”,选择第一个“element”标签,然后再选择“Computed”子标签,如下图所示:

image.png

上图红色方框中显示了html.body.div.p标签的ComputedStyle的值。想要查看哪个元素,点击左边对应的标签就可以了。

布局阶段

有DOM树和DOM树中元素的样式,但这还不足以显示页面,因为我们还不知道DOM元素的几何位置信息。那么接下来就需要计算出DOM树中可见元素的几何位置,这个计算过程叫做布局。

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

1. 创建布局树

DOM树还含有很多不可见的元素,比如head标签,还有使用了display:none属性的元素。所以在显示之前,还要额外地构建一棵只包含可见元素布局树。

布局树的构造过程:

image.png

从上图可以看出,DOM树中所有不可见的节点都没有包含到布局树中。

为了构建布局树,浏览器大体上完成了下面这些工作

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

2. 布局计算

现在我们有了一棵完整的布局树。那么接下来,就要计算布局树节点的坐标位置了。

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

结论

  • 浏览器不能直接理解HTML数据,所以第一步需要将其转换为浏览器能够理解的DOM树结构;
  • 生成DOM树后,还需要根据CSS样式表,来计算出DOM树所有节点的样式;
  • 最后计算DOM元素的布局信息,使其都保存在布局树中。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值