Skip to content

Latest commit

 

History

History
59 lines (42 loc) · 4.24 KB

24.分层和合成机制-为什么CSS动画比JS高效.md

File metadata and controls

59 lines (42 loc) · 4.24 KB

24 | 分层和合成机制:为什么CSS动画比JavaScript高效?

  • CSS和JS影响DOM树生成,继续沿着渲染流水线往下分析,看看DOM树之后发生的事情
  • DOM树生成后,还需要经过布局、分层、绘制、合成、显示等阶段才能显示完整样式页面

渲染引擎分层和合成机制(CSS动画和JS底层工作机制)

  • 显示器显示图像
    • 显示器固定刷新频率60HZ,每秒刷新六十张图片,更新图片来自显卡的前缓冲区
    • 显卡作用: 合成新的图像,将图像保存到后缓冲区中,一旦写到后缓冲区后,系统会让后缓冲区和前缓冲区互换,保证显示器读取到最新显卡合成的图像,一般显卡更新频率和显示器刷新频率一致
  • 帧 VS 帧率
    • 滚动缩放操作时,渲染引擎通过渲染流水线生成新的图片,然后发送到后缓冲区中
    • 大多数设备更新频率一秒六十帧,渲染流水线每秒更新频率为帧率
    • 一次动画过程中如果渲染引擎生成某些帧过久,用户很容易感受到卡顿现象
  • 重排, 重绘,合成
    • 重排需要根据CSSOM和DOM计算布局树,所以需要渲染流水线每个阶段都重新执行,所以渲染效率大幅降低,重绘没有经过重新布局的阶段,但也需要重新计算绘制信息,触发绘制操作之后的操作
    • 合成不需要触发布局和绘制两个阶段,采用GPU加速的话合成效率非常高
    • 按效率看,推荐合成方式优先,不行就回退

分层和合成

  • 页面合成十分复杂,对于一些复杂动画效果,没有分层的话,布局树直接生成目标图片,每次页面都会触发重排和重绘操作,这种绘制效率很可能严重影响页面渲染
  • 分层: 多个图层叠加在一起, 合成:图层合并操作
  • 合成过程显卡处理时间非常短
  • Chrome实现分层和合成机制
    1. Chrome渲染流水线中,分层在生成布局树后,渲染引擎根据布局树特点转化为层树,其是渲染流水线后续流程的基础
    2. 层树每个节点对应一个图层,下一步绘制依赖层树中的节点,渲染阶段将绘制指令组合成一个绘制指令列表,绘制过程完成
    3. 进入光栅化阶段,光栅化: 将绘制列表中的指令生成图片,每个图层对应一张图,合成线程有了图片后,会将这些图片合成为一张,然后发送到后缓冲区,完成分层合成。
    4. 重点: 合成操作在合成线程单独完成,所以不会阻塞主线程执行,这就是主线程卡住,css动画仍能执行的原因
  • 分块
    • 分层宏观上提升渲染效率,分块从微观层面提升渲染效率
    • 合成线程将每个图层分割为大小固定的图块,优先绘制靠近视口的图块,优先级最高的图块渲染也要花费不少时间,因为有纹理上传(计算机内存上传到GPU内存操作会较慢)
    • 首次合成图块使用一个低分辨率的图片,减少纹理上传,首次显示页面内容时先呈现低分辨率内容,然后再进行正常分辨率比例内容图片的展示

利用分层优化代码

  • 对元素进行几何形状变换,透明度变换或者缩放操作,不要用JS操作,用CSS动画渲染(JS操作CSS如果动画时间执行计算时间过长会阻塞主线程的执行和渲染流水线的下行,导致页面动画视觉卡顿)

  • 使用will-change 告诉渲染引擎对该元素做的一些特效变化:

    .box {
    will-change: transform, opacity;
        // 渲染引擎直接通过合成线程处理变换, 不经过主线程,提高渲染效率
    }
    • 但是will-change也会增加额外的内存使用,所以也不能盲目使用(渲染引擎为元素准备独立层,后续阶段会增加一个层结构),浏览器兼容性不太友好,在移动端cpu开销比较大

summary

  • 显示器显示图像原理,帧,帧率概念,生成一帧图像三种方式: 重排,重绘,合成,重排和重绘是在主线程上面执行的,比较耗时的情况会阻塞动画的加载,带来卡顿,合成操作时在合成线程执行的,比较高效且不占用主线程
  • 浏览器怎么合成图层: 分层、分块和合成
  • CSS动画比JS动画高效,使用will-change 优化动画或者特效