“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第5天,点击查看活动详情”
动画的原理
动画的定义是每个静止的画面都叫做帧,以一定的速度(如每秒多少张)连续播放, 肉眼因视觉残象产生错觉,而误以为是活动的画面,比如我们经常看的影视是每秒24帧,游戏一般是每秒30帧。
流畅动画的标准理论上说,FPS 越高,动画会越流畅,目前大多数设备的屏幕刷新率为 60 次/秒,所以通常来讲 FPS 为 60frame/s 时动画效果最好,也就是每帧的消耗时间(帧预算)为 16.67ms,但实际上,浏览器有整理工作要做,因此所有工作需要尽量在 10 ms 内完成,现在新出的移动设备有 90Hz、120Hz,一般FPS越高动画越细腻。
CSS 动画的性能一般要优于 Javascript 动画:GPU 硬件加速 CSS 动画 > 非硬件加速 CSS 动画 > Javascript 动画。
对于动画而言,衡量一个动画的标准也就是 FPS 值。关键是如何计算出每个动画运行时的帧率,使用的是 requestAnimationFrame,正常而言 requestAnimationFrame 这个方法在一秒内会执行 60 次,也就是不掉帧的情况下。假设动画在时间 A 开始执行,在时间 B 结束,耗时 x ms。而中间 requestAnimationFrame 一共执行了 n 次,则此段动画的帧率大致为:n / (B - A)。核心代码如下,能近似计算每秒页面帧率,以及我们额外记录一个 allFrameCount,用于记录 rAF 的执行次数,用于计算每次动画的帧率。
动画使用
css动画中我们常用的有transform、transition,我们先了解一下这两个属性。
transform有四个常用属性是位移translate、缩放scale、旋转rotate、倾斜skew。
transition的作用是过渡,补充中间帧,但是并不是所有属性都能过渡,像display:none => block 没法过渡就没法过渡,一般改成 visibility:hidden => visible,过渡必须要有起始,一般只有一次动画,或者两次,比如 hover 和 非 hover 状态的过渡,或者使用使用 animation声明关键帧。如下:
@keyframes slidein {
from {
transform: translateX(0);
}
to {
transform: translateX(150px);
}
}
还可以使用百分比
@keyframes identifier {
0% { top: 0;}
30% { top: 50px;}
60% { top: 80px; }
100% { top: 120px }
}
animation: 时长丨过渡方式丨延迟丨次数丨方向丨填充模式丨是否暂停丨动画名;
.dome{
animation: slidein 3s forwards
}
深入优化 CSS 动画
完整的像素管道流程 —— JS / CSS > 样式计算 > 布局 > 绘制 > 合成:
JavaScript / CSS 。一般来说,会使用 JavaScript 或者 CSS Animations、Transitions 和 Web Animation API 来实现一些视觉变化的效果。
当然,不一定每帧都总是会经过管道每个部分的处理。我们的目标就是,每一帧的动画,对于上述的管道流程,能避免则避免,不能避免则最大限度优化。
1、 精简 DOM ,合理布局,精简的 DOM 结构在任何时候都是对页面有帮助的。
2、 使用 transform 代替 left、top,减少使用耗性能样式,不同样式在消耗性能方面是不同的,现代浏览器在完成以下四种属性的动画时,会开启了 GPU 硬件加速,动画元素生成了独立的图形层(GraphicsLayer),消耗成本较低。
开启 GPU 加速的方法我们可以使用:
.dome{
will-change: transform
}
这会使声明了该样式属性的元素生成一个图形层,告诉浏览器接下来该元素将会进行 transform 变换,让浏览器提前做好准备.
但是这个属性兼容性和使用起来并不是很好,在一些低端设备上,will-change
会导致很多小问题,譬如会使图片模糊,使用的时候还需要多加测试。
3、 控制频繁动画的层级关系,尽量让需要进行 CSS 动画的元素的 z-index
保持在页面最上方,避免浏览器创建不必要的图形层,能够很好的提升渲染性能。
浏览器为了提升动画的性能,为了在动画的每一帧的过程中不必每次都重新绘制整个页面。在特定方式下可以触发生成一个合成层,合成层拥有单独的 GraphicsLayer。需要进行动画的元素包含在这个合成层中,这样动画的每一帧只需要去重新绘制这个 Graphics Layer 即可,从而达到提升动画性能的目的
综上所述
GPU 硬件加速也会有坑,当我们希望使用利用类似 transform: translate3d() 这样的方式开启 GPU 硬件加速,一定要注意元素层级的关系,尽量保持让需要进行 CSS 动画的元素的 z-index 保持在页面最上方。
Graphics Layer 不是越多越好,每一帧的渲染内核都会去遍历计算当前所有的 Graphics Layer ,并计算他们下一帧的重绘区域,所以过量的 Graphics Layer 计算也会给渲染造成性能影响
—— END ——