1、渲染对象(RenderObject)
一个 DOM 节点对应了一个渲染对
2、渲染层(RenderLayer)
这是浏览器渲染期间构建的第一个层模型,处于相同坐标空间(z轴空间)的渲染对象,
都将归并到同一个渲染层中,因此根据层叠上下文,
不同坐标空间的的渲染对象将形成多个渲染层,以体现它们的层叠关系
(布局视觉上的层级 index1 index2 opcity之类的导致看不见了)
根元素 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 应用动画
3、图形层(GraphicsLayer)
GraphicsLayer 其实是一个负责生成最终准备呈现的内容图形的层模型,
它拥有一个图形上下文(GraphicsContext),GraphicsContext 会负责输出该层的位图。
存储在共享内存中的位图将作为纹理上传到 GPU,最后由 GPU 将多个位图进行合成,
然后绘制到屏幕上,此时,我们的页面也就展现到了屏幕上。
但它并不直接处理渲染层,而是处理合成层
其实可以把它当作合成层看待
4、合成层(CompositingLayer)
满足某些特殊条件的渲染层,会被浏览器自动提升为合成层。
合成层拥有单独的 GraphicsLayer
3D transforms:translate3d、translateZ 等
video、canvas、iframe 等元素
通过 Element.animate() 实现的 opacity 动画转换
通过 СSS 动画实现的 opacity 动画转换
position: fixed
具有 will-change 属性
对 opacity、transform、fliter、backdropfilter 应用了 animation 或者 transition
5、隐式合成
当出现一个合成层后,层级顺序高于它的堆叠元素就会发生隐式合成。
6、层爆炸
当这些不符合预期的合成层达到一定量级时,就会变成层爆炸。
7、层压缩
在屏幕内发生了交叠,浏览器的层压缩机制,
会将隐式合成的多个渲染层压缩到同一个 GraphicsLayer 中进行渲染
Chrome Devtools 如何查看合成层
More tools -> Layers
合成层的位图,会交由 GPU 合成,比 CPU 处理要快得多;
当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层;
元素提升为合成层后,transform 和 opacity 才不会触发 repaint,
如果不是合成层,则其依然会触发 repaint。
绘制的图层必须传输到 GPU,这些层的数量和大小达到一定量级后,
可能会导致传输非常慢,进而导致一些低端和中端设备上出现闪烁;
隐式合成容易产生过量的合成层,每个合成层都占用额外的内存,
而内存是移动设备上的宝贵资源,过多使用内存可能会导致浏览器崩溃,让性能优化适得其反。
1、动画使用 transform 实现
对于一些体验要求较高的关键动画,比如一些交互复杂的玩法页面,
存在持续变化位置的 animation 元素,
我们最好是使用 transform 来实现而不是通过改变 left/top 的方式。这样做的原因是,
如果使用 left/top 来实现位置变化,animation 节点和 Document 将被放到了同一个
GraphicsLayer 中进行渲染,持续的动画效果将导致整个 Document 不断地执行重绘,而使用
transform 的话,能够让 animation 节点被放置到一个独立合成层中进行渲染绘制,
动画发生时不会影响到其它层。并且另一方面,动画会完全运行在 GPU 上,相比起 CPU
处理图层后再发送给显卡进行显示绘制来说,这样的动画往往更加流畅。
2、减少隐式合成
虽然隐式合成从根本上来说是为了保证正确的图层重叠顺序,但具体到实际开发中,
隐式合成很容易就导致一些无意义的合成层生成,
归根结底其实就要求我们在开发时约束自己的布局习惯,避免踩坑。
3、减小合成层的尺寸
举个简单的例子,分别画两个尺寸一样的 div,但实现方式有点差别
:一个直接设置尺寸 100x100,
另一个设置尺寸 10x10,然后通过 scale 放大 10 倍,
并且我们让这两个 div 都提升为合成层: