在之前的文章《高频面试问题》中,浏览器从输入url到页面显示发生了什么,我们大致介绍了浏览器的渲染过程。今天,我们将深入研究这一部分。
对于很多前端开发人员来说,平时的工作侧重于业务开发,对于浏览器的渲染阶段可能不是很了解。其实这个阶段很重要。了解了浏览器的渲染过程,可以让我们知道自己编写的HTML、CSS、JS代码是如何解析,最终渲染成页面的。在优化页面性能时有相应的解决方案。
我们先来看一个问题:
HTML、CSS、JS文件在浏览器中是如何转换成页面的?
如果不能回答,那就往下看。
根据渲染的时间顺序,渲染过程可以分为以下几个子阶段:构建DOM树、样式计算、布局阶段、分层、栅格化和复合显示。
我们来详细看看每个阶段都做了什么。
1.构建DOM树
HTML文档描述了一个页面的结构,但是浏览器不能直接理解和使用HTML,所以需要通过HTML解析器将HTML转换成浏览器能理解的结构——DOM树。
HTML中的一切都是一个节点,每个节点都有层次关系,相互连接形成一棵DOM树。
构造过程:读取HTML文档的字节,将字节转换为字符,根据字符确定令牌,将令牌转换为节点,基于节点构建DOM树。请参考下图:
打开Chrome的开发者工具,在控制台输入document并回车,就可以看到一个完整的DOM树结构,如下图所示:
控制台上打印的DOM结构与HTML内容几乎相同,但与HTML不同的是,DOM是存储在内存中的树形结构,其内容可以通过JavaScript查询或修改。
2.风格计算
在计算样式的这个阶段,计算DOM节点中每个元素的表达式样式。
2.1解析CSS
CSS样式可以通过以下三种方式引入:
通过link引用外部的CSS文件style 标签内的CSS元素的style属性内嵌的CSS
就像HTML一样,浏览器无法直接理解明文的CSS样式,需要通过CSS解析器将CSS解析成样式表结构,也就是我们常说的CSS SOM树。
样式表结构还具有查询和修改功能:
document.styleSheets
2.2属性值的标准化
属性值的标准化从字面上理解有点困难。让我们以下面的例子来看看什么是属性值的标准化:
在编写CSS样式时,我们经常使用白色、红色等。设置颜色属性值时。但这种数值浏览器的渲染引擎并不容易理解,需要将所有数值转换成渲染引擎容易理解的标准化计算值。这个过程就是属性值的标准化。
白色的标准化值是rgb(255,255,255)
2.3计算DOM树中每个节点的样式
标准化样式的属性值后,我们需要计算每个节点的样式属性。在这个阶段,我们需要明确CSS的两个规则:
继承规则:每个DOM节点都包含有父节点的样式层叠规则:层叠是CSS的一个基本特征,是一个定义了如何合并来自多个源的属性值的算法。
样式计算阶段是计算DOM节点中每个元素的具体样式。在计算过程中,要遵守CSS继承和层叠两个规则。
这个阶段的最终输出是每个DOM节点的样式,它保存在ComputedStyle的结构中。
3.布局阶段
经过以上两步,我们得到了DOM树和DOM树中元素的样式。接下来,我们需要计算DOM树中可见元素的几何位置。这个计算过程就是布局。
3.1创建布局树
DOM树包含一些不可见的元素,比如head标签和带有display:none属性集的元素,所以我们需要构建一个额外的布局树,只包含可见的元素。
构造过程:从DOM树的根节点开始遍历,将所有可见节点添加到布局树中,忽略不可见节点。
3.2布局计算
此时,我们已经构建了布局树,我们可以开始计算布局树节点的坐标位置。从根节点开始遍历,结合上面计算的样式确定页面上每个节点对象的具体大小和位置,并将这些信息保存在布局树中。
布局阶段的输出是一个盒子模型,它可以准确地捕捉屏幕上每个元素的确切位置和大小。
4.分层
现在我们有了布局树,知道了每个元素的具***置信息,我们还不能开始绘制页面,因为会有3D变换、页面滚动或者用z-index进行Z轴排序等复杂的效果。为了更方便的实现这些效果,渲染引擎还需要为特定的节点生成一个专用的图层和对应的LayerTree。
在Chrome浏览器中,我们可以打开开发者工具,选择Elements-Layers选项卡,就可以看到页面的层次感,如下图所示:
浏览器的页面其实分为很多层,叠加在一起就形成了最终的页面。
到目前为止,我们已经建立了两棵树:布局树和层树。让我们来看看这两棵树的关系:
通常,不是布局树的每个节点都包含一个层。如果节点没有对应的层,则该节点从属于父节点的层。
节点必须满足什么条件才能提升到单独的层?只要满足下列条件之一:
拥有层叠上下文属性的元素会被提升为单独的一个图层需要剪裁(clip)的地方也会被创建为图层。
5.图层绘制
在构建层树之后,渲染引擎将绘制层树中的每个层。
渲染引擎实现图层绘制,将一个图层的绘制拆分成许多小的绘制指令,然后用这些指令依次形成一个绘制列表。
6.光栅操作
绘制图层时,会生成一个绘图列表,它只是一个用来记录绘图顺序和绘图指令的列表。实际上,绘制操作是由渲染引擎中的合成线程来完成的。
我们通过下图来看看主渲染线程和合成线程之间的关系:
当图层的图纸列表准备好后,主线程会将图纸列表提交给合成线程,合成线程开始工作。
首先,合成线程将图层划分为瓦片,瓦片大小通常为256256或512512。
然后合成线程会优先根据视口附近的图块生成位图,生成位图的实际操作是通过光栅化来完成的。光栅化是指将拼贴转换为位图。拼贴是最小的栅格化单位。渲染进程维护一个光栅化的线程池,所有图块光栅化都在线程池中执行。操作模式如下图所示:
7.合成和显示
一旦所有图块被光栅化,合成线程将生成绘制图块的命令——“绘制四边形”,然后将该命令提交给浏览器进程。
浏览器中有一个叫viz的组件,用来接收composition线程发来的DrawQuad命令,然后根据命令执行。DrawQuad命令将页面内容绘制到内存中,然后在屏幕上显示内存。
多年发展老码农福利礼品:网页制作,网站开发,web前端开发,HTML+CSS+JavaScript从最基础开始。JQuery,Vue,React,Ajax,node,angular framework等。都是移动小程序项目实战时整理出来的【视频+工具+电子书+系统路线图】。有需要的伙伴可以私信我,发送“前端”3秒后,就可以获得接收地址,发送给每一个对编程感兴趣的小伙伴。
8.摘要
完整的渲染过程可以总结如下:
1、渲染进程将HTML内容转换为浏览器能够读懂的DOM树结构。2、渲染引擎将CSS样式表转化为浏览器可以理解的styleSheets,计算出DOM节点的样式。3、创建布局树,并计算所需元素的布局信息。4、对布局树进行分层,并生成分层树。5、为每个图层生成绘制列表,并将其提交到合成线程。6、合成线程将图层分图块,并栅格化将图块转换成位图。7、合成线程发送绘制图块命令给浏览器进程。浏览器进程根据指令生成页面,并显示到显示器上。
在渲染的过程中还有两个我们经常听到的概念:重排和重绘。本文不赘述,下一篇再详细介绍。
本文来自玩味不尽投稿,不代表舒华文档立场,如若转载,请注明出处:https://www.chinashuhua.cn/24/644478.html