从浏览器渲染层面解析 CSS3 动效优化原理

发布于 2025-02-25 01:25:30 字数 5982 浏览 8 评论 0

在 h5 开发中,我们经常会需要实现一些动效来让页面视觉效果更好,谈及动效便不可避免地会想到动效性能优化这个话题:

  • 减少页面 DOM 操作,可以使用 CSS 实现的动效不码出一行 js 代码
  • 使用绝对定位脱离让 DOM 脱离文档流,减少页面的重排(relayout)
  • 使用 CSS3 3D 属性开启硬件加速

那么,CSS3 与动效优化有什么关系呢,本文将从浏览器渲染层面讲述 CSS3 的动效优化原理

浏览器页面展示过程

首页,我们需要了解一下浏览器的页面展示过程:

浏览器页面展示过程

  • Javascript:主要负责业务交互逻辑。
  • Style: 根据 CSS 选择器,对每个 DOM 元素匹配对应的 CSS 样式。
  • Layout: 具体计算 DOM 元素显示在屏幕上的大小及位置。
  • Paint: 实现一个 DOM 元素的可视效果(颜色、边框、阴影等),一般来说由多个渲染层完成。
  • Composite: 当每个层绘制完成后,浏览器会将所有层按照合理顺序合并为一个图层,显示到屏幕。 本文我们将重点关注 Composite 过程。

浏览器渲染原理

在讨论 Composite 之前,我们还需要了解一下浏览器渲染原理

浏览器渲染原理

从该图中,我们可以发现:

  • DOM 元素Layout Object 存在一一对应的关系
  • 一般来说,拥有相同坐标空间的 Layout Object 属于同一个 Paint Layer (渲染层) ,通过 position、opacity、filter 等 CSS 属性可以创建新的 Paint Layer
  • 某些特殊的 Paint Layer 会被认为是 Composite Layer (合成层/复合层) ,Composite Layer 拥有单独的 Graphics Layer (图形层) ,而那些非 Composite Layer 的 Paint Layer,会与拥有 Graphics Layer 的父层共用一个

Graphics Layer

我们日常生活中所看到屏幕可视效果可以理解为:由多个位图通过 GPU 合成渲染到屏幕上,而位图的最小单位是像素。如下图:

那么位图是怎么获得的呢, Graphics Layer 便起到了关键作用,每个 Graphics Layer 都有一个 Graphics Context , 位图是存储在共享内存中, Graphics Context 会负责将位图作为 纹理 上传到 GPU 中,再由 GPU 进行合成渲染。如下图:

CSS 在浏览器渲染层面承担了怎样的角色

大多数人对于 CSS3 的第一印象,就是可以通过 3D(如 transform) 属性来开启硬件加速,许多同学在重构某一个项目时,考虑到动画性能问题,都会倾向:

将 2Dtransform 改为 3Dtransform 2.将 left ( top、bottom、right ) 的移动改为 3Dtransform,但开启硬件加速的 底层原理 其实就在于 将 Paint Layer 提升到了 Composite Layer

以下的几种方式都用相同的作用:

  1. 3D 属性开启硬件加速(3d-transform)
  2. will-change: (opacity、transform、top、left、bottom、right)
  3. 使用 fixed 或 sticky 定位
  4. 对 opacity、transform、filter 应用了 animation(actived) or transition(actived),注意这里的 animation 及 transition 需要是处于 激活状态 才行

我们来写两段 demo 代码,带大家具体分析一下实际情况

demo1. 3D 属性开启硬件加速 (3d-transform)

.composited{
  width: 200px;
  height: 200px;
  background: red;
  transform: translateZ(0)
}
</style>

<div class="composited">
  composited - 3dtransform
</div>

可以看到是因为使用的 CSS 3D transform,创建了一个复合层

demo2. 对 opacity、transform、filter 应用 animation(actived) or transition(actived)

<style>
@keyframes move{
  0%{
    top: 0;
  }
  50%{
    top: 600px;
  }
  100%{
    top: 0;
  }
}
@keyframes opacity{
  0%{
    opacity: 0;
  }
  50%{
    opacity: 1;
  }
  100%{
    opacity: 0;
  }
}

#composited{
  width: 200px;
  height: 200px;
  background: red;
  position: absolute;
  left: 0;
  top: 0;

}
.both{
  animation: move 2s infinite, opacity 2s infinite;
}
.move{
  animation: move 2s infinite;
}
</style>

<div  id="composited" class="both">
  composited - animation
</div>
<script>
setTimeout(function(){
  const dom = document.getElementById('composited')
  dom.className = 'move'
},5000)
</script>

这里我们定义了两个 keyframes(move、opacity) ,还有两个 class(both、move) ,起初 #compositedclassName = 'both' ,5 秒延时器后, className = 'move' ,我们来看看浏览器的实际变化。

起初: #composited 创建了一个复合层,并且运动时 fps 没有波动,性能很稳定

起初

5 秒后: 复合层消失,运动时 fps 会发生抖动,性能开始变得不再稳定

5 秒后

如何查看复合层及 fps

在浏览器的 Dev Tools 中选择 More tools ,并勾选 Rendering 中的 FPS meter

动画性能最优化

之前,我们提到了页面呈现出来所经历的渲染流水线,其实从性能方面考虑, 最理想的渲染流水线是没有布局和绘制环节的 ,为了实现上述效果,就需要只使用那些仅触发 Composite 的属性。

目前,只有两个属性是满足这个条件的: transformsopacity (仅部分浏览器支持)。
相关信息可查看: css Triggers

总结

提升为合成层简单说来有以下几点好处:

  • 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
  • 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
  • 对于 transform 和 opacity 效果,部分浏览器不会触发 Layout 和 Paint, 相关信息可查看: css Triggers

缺点:

  • 创建一个新的合成层并不是免费的,它得消耗额外的内存和管理资源。
  • 纹理上传后会交由 GPU 处理,因此我们还需要考虑 CPU 和 GPU 之间的带宽问题、以及有多大内存供 GPU 处理这些纹理的问题

大多数人都很喜欢使用 3D 属性 translateZ(0) 来进行所谓的硬件加速,以提升性能。但我们还需要切实的去分析页面的实际性能表现,不断的改进测试,这样才是正确的性能优化途径。

参考资料

无线性能优化:Composite - 淘系前端团队

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

贱贱哒

暂无简介

文章
评论
524 人气
更多

推荐作者

闻呓

文章 0 评论 0

深府石板幽径

文章 0 评论 0

mabiao

文章 0 评论 0

枕花眠

文章 0 评论 0

qq_CrTt6n

文章 0 评论 0

红颜悴

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文