渲染层 层合成 层压缩 层爆炸
# 渲染层
在 DOM 树中每个节点都会对应一个渲染对象(RenderObject),当它们的渲染对象处于相同的坐标空间(z 轴空间)时,就会形成一个 RenderLayers,也就是渲染层。渲染层将保证页面元素以正确的顺序堆叠,这时候就会出现层合成(composite),从而正确处理透明元素和重叠元素的显示。
处于相同坐标空间(z轴空间)的渲染对象,都将归并到同一个渲染层中,因此根据层叠上下文,不同坐标空间的的渲染对象将形成多个渲染层,以体现它们的层叠关系。所以,对于满足形成层叠上下文条件的渲染对象,浏览器会自动为其创建新的渲染层。能够导致浏览器为其创建新的渲染层的,包括以下几类常见的情况:
- 根元素 document
- 有明确的定位属性(relative、fixed、sticky、absolute)
- opacity < 1
- 有 CSS fliter 属性
- 有 CSS mask 属性
- 有 CSS mix-blend-mode 属性且值不为 normal
- 有 CSS transform 属性且值不为 none
- backface-visibility 属性为 hidden
- 有 CSS reflection 属性
- 有 CSS column-count 属性且值不为 auto或者有 CSS column-width 属性且值不为 auto
- 当前有对于 opacity、transform、fliter、backdrop-filter 应用动画
- overflow 不为 visible
DOM 节点和渲染对象是一一对应的,满足以上条件的渲染对象就能拥有独立的渲染层。当然这里的独立是不完全准确的,并不代表着它们完全独享了渲染层,由于不满足上述条件的渲染对象将会与其第一个拥有渲染层的父元素共用同一个渲染层,因此实际上,这些渲染对象会与它的部分子元素共用这个渲染层。
# 图形层(GraphicsLayer)
GraphicsLayer 其实是一个负责生成最终准备呈现的内容图形的层模型,它拥有一个图形上下文(GraphicsContext),GraphicsContext 会负责输出该层的位图。存储在共享内存中的位图将作为纹理上传到 GPU,最后由 GPU 将多个位图进行合成,然后绘制到屏幕上,此时,我们的页面也就展现到了屏幕上。 所以 GraphicsLayer 是一个重要的渲染载体和工具,但它并不直接处理渲染层,而是处理合成层。
# 合成层
合成就是将页面的各个部分分成多个层、单独光栅化(浏览器根据文档的结构、每个元素的样式、页面的几何形状和绘制顺序转换为屏幕上的像素的过程)它们并在合成器线程中合成为一个页面的技术。
观察页面的图层结构,需要在 Chrome 开发工具中打开自定义菜单,然后在 More tools 中选择 Layers 选项
拥有一些特定属性的渲染层,会被浏览器自动提升为合成层。合成层拥有单独的图层(GraphicsLayer),和其他图层之间无不影响。而其它不是合成层的渲染层,则和第一个拥有图层的父层共用一个,也就是普通文档流中的内容,常见的提升为合成层的属性
- 设置 transform: translateZ(0),注意它必须是 translateZ,因为它使用 GPU 来计算 perspective distortion(透视失真)。perspective 在 3D 设计中是一个重要的属性。如果使用 translateX 或 translateY,元素将会被绘制在普通文档流中
- backface-visibility: hidden 指定当元素背面朝向观察者时是否可见 demo。
- will-change 该属性告诉浏览器该元素会有哪些变化,这样浏览器可以提前做好对应的优化准备工作。当该属性的值为 opacity、transform、top、left、bottom、right 时 demo。
- video、canvas、iframe 等元素
# 隐式合成
隐式合成就是特定场景下,存在渲染层会被默认提升为合成层的情况: 一个或多个非合成元素应出现在堆叠顺序上的合成元素之上,会被提升为合成层。
简单解释就是:a, b, c, d 4个 div 堆叠到一起,a 的 z - index 最小,处于最下层,这时候给 a 用了可以提升合成层的属性,这时候尽管 bcd 这三个没有主动用来提升合成层,浏览器也会默认给他们都提升到合成层
提升后的合成层位于 Document 上方,假如没有隐式合成,原本应该处于上方的 div 就依然还是跟 Document 共用一个 GraphicsLayer,层级反而降了,就出现了元素交叠关系错乱的问题,为了纠正错误的交叠顺序,浏览器必须让原本应该”盖在“它上边的渲染层也同时提升为合成层
# 层压缩与层爆炸
一些产生合成层的原因太过于隐蔽了,尤其是隐式合成。在平时的开发过程中,我们很少会去关注层合成的问题,很容易就产生一些不在预期范围内的合成层,当这些不符合预期的合成层达到一定量级时,就会变成层爆炸
层爆炸会占用 GPU 和大量的内存资源,严重损耗页面性能,因此盲目地使用 GPU 加速,结果有可能会是适得其反
面对这种问题,浏览器也有相应的应对策略,如果多个渲染层同一个合成层重叠时,这些渲染层会被压缩到一个 GraphicsLayer 中,以防止由于重叠原因导致可能出现的“层爆炸”
浏览器的层压缩机制,会将隐式合成的多个渲染层压缩到同一个 GraphicsLayer 中进行渲染,也就是说,上方的三个 bcd div 最终会处于同一个合成层中,这就是浏览器的层压缩。
浏览器的自动层压缩并不是万能的,有很多特定情况下,浏览器是无法进行层压缩的,具体见:https://fed.taobao.org/blog/2016/04/26/performance-composite/
- 01
- 2023/07/03 00:00:00
- 02
- 2023/04/22 00:00:00
- 03
- 2023/02/16 00:00:00