浏览器复习-渲染
浏览器渲染流程
构建DOM树、构建渲染树、布局、绘制、合成
- 构建DOM树 浏览器将HTML解析成树形结构的DOM树,一般来说,这个过程发生在页面初次加载,或页面JavaScript修改了DOM节点结构的时候
- 构建渲染树 浏览器将CSS解析成树形结构的CSSOM树,再和DOM树合并成渲染树
- 布局(Layout) 浏览器根据渲染树所体现的节点、各个节点的CSS定义以及它们的从属关系,计算出每个节点在屏幕中的位置。web页面中元素的布局是相对的,在页面元素位置、大小发生变化时,往往会导致其他节点联动,需要重新计算布局,这时候布局过程一般被称为回流(Reflow)
- 绘制(paint)
遍历渲染树,调用渲染器的
paint()
方法在屏幕上绘制出节点内容,本质上是一个像素填充的过程。这个过程也出现于回流或一些不影响布局的CSS修改引起的屏幕局部重画,这时候被称为重绘(Reapint)。实际上,绘制过程是在多个层上完成的,这些层我们称为渲染层(RenderLayer) - 合成(Composite) 多个绘制后的渲染层按照恰当的重叠顺序进行合并,而后生成位图,最终通过显卡展示到屏幕上
浏览器渲染原理
从浏览器的渲染过程中知道,页面HTML会解析成DOM树,每个HTML元素对应了树结构上的一个node节点。而从DOM树转化到一个个的渲染层,并最终执行合并、绘制的过程中,中间其实还存在一些过渡的数据结构,它们记录了DOM树到屏幕图形的转化原理,其本质也就是树结构到层结构的演化
渲染对象(RenderObject)
一个DOM节点对应了一个渲染对象,渲染对象依然维持着DOM树的树形结构。一个渲染对象知道如何绘制一个DOM节点的内容,它通过向一个绘图上下文(GraphicsContext)发出必要的绘制调用来绘制DOM节点
渲染层(RenderLayer)
这是浏览器渲染期间构建的第一个层模型,处于相同坐标空间(z轴)的渲染对象,都将归并到同一个渲染层中,因此根据层叠上下文,不同坐标的渲染对象将形成多个渲染层,以体现它们的层叠关系。所以,对于满足形成层叠上下文条件的渲染对象,浏览器会自动为其创建新的渲染层。
创建新的渲染层的情况:
- 根元素(
document
) - 有明确的定位属性(
relative
fixed
absolute
sticky
) opacity
< 1- CSS
filter
mask
transform
不为none
overflow
不为visible
DOM节点和渲染对象是一一对应的,满足以上条件的渲染对象就能拥有独立的渲染层。此外,不满足上述条件的渲染对象将会与其第一个拥有渲染层的父元素共用一个渲染层
图形层(GraphicsLayer)
GraphicsLayer其实是一个负责生成最终准备呈现的内容图形的层模型,它拥有一个图形上下文(GraphicsContext),GraphicsLayer会负责输出该层的位图。存储再共享内存中的位图将作为纹理上传到GPU,最后有GPU将多个位图进行合成,然后绘制到屏幕上
合成层(CompositingLayer)
满足某些特殊条件的渲染层,会被浏览器自动提升为合成层。合成层拥有独立的GraphicsLayer,而其他不是合成层的渲染层,则和其第一个拥有GraphicsLayer的复层共用一个。
隐式合成&&层爆炸
除了显式设定一些属性来将渲染层提升合成层外,还有一些隐式合成,部分渲染层在一些特定的场景下会被默认提升为合成层:
两个absolute
定位的div
在屏幕上交叠了,根据z-index
的关系,其中一个div
就会盖在了另外一个上边。这个时候,如果处于下方的div
被加上了CSS
属性:transform: translateZ(0)
,就会被浏览器提升为合成层。提升后的合成层位于Document
上方,假如没有隐式合成,原本应该处于上方的div
就依然还是跟 Document
共用一个GraphicsLayer
,层级反而降了,就出现了元素交叠关系错乱的问题。所以为了纠正错误的交叠顺序,浏览器必须让原本应该”盖在“它上边的渲染层也同时提升为合成层。
一些产生合成层的原因太过于隐蔽了,尤其是隐式合成。在平时的开发过程中,我们很少会去关注层合成的问题,很容易就产生一些不在预期范围内的合成层,当这些不符合预期的合成层达到一定量级时,就会变成层爆炸
消除隐式合成就是要消除元素交叠,拿这个DEMO来说,只需要给上层div
的z-index
属性设置一个较高的数值,就能让它高于页面中其他元素,自然也就没有合成层提升的必要了
当然了,面对这种问题,浏览器也有相应的应对策略,层压缩。如果多个渲染层同一个合成层重叠时,这些渲染层会被压缩到一个GraphicsLayer
中,以防止由于重叠原因导致可能出现的层爆炸
回流
当对DOM的修改引发DOM几何尺寸发生变化的时候,就会发生回流
具体表现在以下操作:
- 设置
width
、height
、padding
、margin
、border
、left
等属性 - 添加或删除dom节点
- 读写
offset-*
、scroll-*
、client-*
属性。浏览器为了获取这些值,需要进行回流操作 - 调用
getCompoutedStyle
、getBoundingClientRect
、scrooTo
方法
发生回流时,将重新渲染DOM树,比较耗时
重绘
当对DOM的修改导致了样式的变化,比如修改了color
,并没有影响几何属性,这时会触发重绘
由于没有导致DOM几何属性的变化,因此元素的位置信息不需要更新,从而省去布局的过程,相较于回流比较节省资源开销
合成
利用CSS3的transform
、opacity
、filter
这些属性就可以实现合成的效果,也就是大家常说的GPU加速
- 能够充分发挥GPU的优势。合成线程生成位图的过程中会调用线程池,并在其中使用GPU进行加速生成
- 独占一个
GraphicsLayer
提升为合成层的情况:
translate3d
translateZ
video
canvas
iframe
- 通过
Element.animate()
实现的opacity
动画转换 - 通过CSS动画实现的
opacity
动画转换 - CSS
will-change
属性 - 对
opacity
transform
filter
应用了animation
或者transition