在一周前我写了 从输入URL到页面呈现发生了什么?(网络请求)
那么完成了网络请求和响应,如果响应头中的Content-Type的值是text/html,那么就下来就是浏览器的渲染了。
浏览器渲染又分为**解析算法**和**渲染过程**
  • 解析:构建DOM树 => 样式计算 => 生成布局树
  • 渲染:建立图层树 => 生成绘制列表 => 生成图块并栅格化
  1. 构建DOM树
    浏览器是无法理解HTML字符串的,所以浏览器第一个步骤是将这一系列字节流解析为DOM树(DOM树本质上是一个以document为根节点的多叉树)
    图片说明
  2. 样式计算
    浏览器同样也无法理解CSS,渲染引擎将CSS样式表转化为浏览器可以理解的styleSheets,计算出DOM节点的样式。

图片说明

  • 上面这张图可以看出,有一些CSS样式的数值并不容易被渲染引擎理解,所以需要将所有的值转换为标准化的计算值,这个过程就是属性值标准化

  • 处理完成后再处理样式的继承层叠

  • 值得注意的是,在计算完样式后,所有的样式值会被挂到window.computedStyle当中,也就是可以通过JS来获取计算后的样式。

  1. 生成布局树
    现在已经生成了DOM树DOM样式,接下来浏览器要通过布局系统确定元素的位置,生成布局树(遍历生成DOM树节点,将其添加到布局树中 => 计算布局树节点的位置)。
    值得注意的是,布局树只包含可见元素,对于head标签和display:none的元素,将不会放入其中。

  2. 建立图层树
    当我们拥有了DOM节点、样式和布局就可以绘制页面了吗?
    当然不,页面中有很多复杂的效果,如一些复杂的3D动画,使用z-indexing的z轴排序等等。为了解决这些复杂的问题,浏览器会在构建完布局树后对特定的节点进行分层,构建图层树。

图层树根据什么进行创建?
一般情况下,节点的图层会默认属于父亲节点的图层(合成层)。

什么时候会提升为一个单独的合成层?
分为显示合成隐式合成

显式合成:(拥有层叠上下文的节点、需要被剪裁的地方)

拥有层叠上下文的节点:
HTML根元素本身就具有层叠上下文
普通元素设置position为static,并且设置了z-index属性,产生层叠上下文
元素opacity值不是1
元素transform值不是none
元素filter值不是none
元素isolation值不是isolate
will-change指定的属性值为以上任意一个

需要剪裁的地方:比如一个100*100的div,你在里面放了非常多的文字,那么超出div范围的文字部分就需要被剪裁,如果出现滚动条,那么滚动条会单独提升为一个图层。

隐式合成:
层叠低的节点被提升为单独的图层后,所有层叠等级比它高的节点都会成为一个单独的图层。

隐式合成其实隐藏着巨大的风险,如果在一个大型应用中,当一个z-index比较低的元素被提升为单独图层后,层叠在它上面的元素都会被提升为单独图层,可能会增加上千个图层,大大增加内存的压力,甚至直接让页面崩溃,这就是层爆炸的原理。

  1. 生成绘制列表
    接下来渲染引擎会将图层的绘制拆分为一个个绘制指令,比如先画背景、再描绘边框等等,然后这些绘制指令会按照顺序组成一个绘制列表,相当于给后面的绘制操作做了一波计划。
  2. 生成图块并栅格化
    最后开始绘制操作,实际上渲染进程中绘制操作是由专门的线程完成的,这个线程叫合成线程。
    生成图块:首先,通常一个页面可能很大,但是用户看到的只有一部分,我们把用户可以看到的这个部分叫做视口(viewport)。有的图层可能很大,要滑很久才能滑到底,如果一口气全部绘制出来是相当浪费性能的,也没有这个必要。所以,合成线程要做的第一件事就是将图层分块,这些块的大小一般不会特别大,通常是256256或者512512这个规格,这样可以大大加速页面的首屏展示。
    栅格化(生成位图):渲染进程中专门维护了一个栅格化线程池,专门负责把图块栅格化,合成进程会按照视口附近的图块来优先生成位图,生成位图的过程实际上都会使用GPU进行加速,生成的位图最后发送给合成进程。
  3. 显示
    最后,合成进程发送绘制图块指令给浏览器进程,浏览器根据指令生成页面,并显示到浏览器上,渲染过程完成。

最后~
图片说明