CSS 动画属性在日常工作中很常用,带来的问题也是显而易见的,本文讲述了如何优化动画性能。
CSS3 的 animation 和 transition 大家应该都不陌生,这是写动画效果时经常用到的两个属性。
语法:
animation: name duration timing-function delay iteration-count direction fill-mode play-state;
示例:给类名为 box1 的 DOM 设置一个动画,动画3秒完成,效果是向右移动 1200px。
@keyframes move {
/* 初始状态 */
0% {
transform: translate(0, 0);
}
/* 结束状态 */
100% {
transform: translate(1200px, 0);
}
}
.box1 {
background-color: #f34;
/* 调用动画,move为动画名,持续时间3s */
animation: move 3s;
}
用来控制动画速度的方法。
语法:
transition: transition-property transition-duration transition-timing-function transition-delay
示例:鼠标悬浮在 box1 1.9 秒后,box1的宽度在0.25秒变成200px,悬浮 2 秒后背景色改变。
.box1 {
width: 100px;
height: 100px;
border: 3px solid black;
margin: 10px 0px 0px 10px;
transition: width .25s linear 1.9s, background 1s 2s;
}
.box1:hover {
width: 200px;
background-color: blue;
}
通常咱们能用 CSS 动画实现的简单效果,就避免引入大体积的 JS 动画库代码,所以 CSS 动画经常用到。但是动画多了会造成页面性能降低,这是无法避免的,但是可以优化。
使用 GPU 加速优化的是动画的流畅度,过度使用会带来性能问题。
浏览器的 GPU 加速功能是将需要进行动画的元素提升到一个独立的层(layer),这样就可以避免浏览器进行重新布局(Reflow)和绘制(Repaint)。
将原先的浏览器使用 CPU 绘制位图来实现的动画效果转为让 GPU 使用图层合成来实现,如果两张图层内部没有发生改变,浏览器就不再进行布局和绘制,直接使用 GPU 的缓存来绘制每个图层,GPU 只负责将各个图层合成来实现动画,这就可以充分利用 GPU 的资源和优势,减轻 CPU 的负载,可以使动画更流畅。通过改变两张图片之间的相对位置代替绘制一张图片的每一帧来实现动画,虽然视觉效果相同,但省去了许多绘制的时间。
为了让浏览器将动画元素提升到一个独立的层,可以使用 transform
和 opacity
属性来实现动画,当设置了这两个属性之一时,浏览器会自动进行这一优化操作(透明度的变化可以通过GPU改变a通道来实现,不需要浏览器进行重绘)。对于动画,可以使用 transform
来代替改变 left 和 top 属性。
触发 GPU 硬件加速的 CSS 属性:transform(如translate、3D的translate3D/scaleZ…)
、opacity
、filter
。
以上这几种触发的属性,被属性业界往往称之为 hack 加速法。有时不需要 z 轴变化,但是为了触发 GPU ,假模假样加了声明,对此我们有更好的做法:will-change
。顾名思义,就是告诉大家“我要变形了”,十分友好。
当我们通过某些行为(点击、移动或滚动)触发页面进行大面积绘制的时候,浏览器往往是没有准备的,只能被动使用 CPU 去计算与重绘,由于没有事先准备,于是出现掉帧、卡顿的问题。而 will-change 则是真正的行为触发之前就通知浏览器做好准备,浏览器马上把 GPU 给拉上了,从容应对即将到来的变形。
注意
1.使用GPU渲染会影响字体的抗锯齿效果。这是因为GPU和CPU具有不同的渲染机制,即使最终硬件加速停止了,文本还是会在动画期间显示的很模糊。
2.使用了GPU可以优化动画但是不要滥用,会有内存问题。
有些节点,当你改变他时,会需要重新布局(这也意味着需要重新计算其他被影响的节点的位置和大小)。这种情况下,被影响的DOM树越大(可见节点),重绘所需要的时间就会越长,而渲染一帧动画的时间也相应变长。所以需要尽力避免这些属性。
这些属性的共同特点就是可能修改整个节点的大小或位置
,所以会触发重布局。
一些常见的触发“重布局”属性:
(1)盒子模型相关
width
、height
、padding
、margin
、display
、border-width
、border
、min-height
(2)定位属性及浮动
top
、bottom
、left
、right
、position
、float
、clear
(3)改变节点内部文字结构
text-align
、overflow-y
、font-weight
、overflow
、font-family
、line-height
、vertival-align
、white-space
、font-size
有些属性不会修改节点的大小和位置,即不会触发重布局。具体情况具体分析,如果节点内部的渲染效果进行了改变而已,则只需要重绘。
在移动端,重绘也会很慢。因为移动端 CPU 不如 PC 端,所以绘画的时间更长。而且 CPU 与 GPU 之间的有较大的带宽限制,所以纹理的上传需要一定时间。
只触发“重绘”的属性:color
、border-style
、border-radius
、visibility
(display:visibility)、text-decoration
、background
、background-image
、background-position
、background-repeat
、background-size
、outline-color
、outline
、outline-style
、outline-width
、box-shadow
。
尽量让需要进行 CSS 动画的元素的 z-index 保持在页面最上方,避免浏览器创建不必要的图形层,这样可以很好的提升渲染性能。