WEB 动画世界已经变成了一个庞大的工具和技术丛林,像 GSAP 和 Framer Motion 以及 React Spring 这样的库如雨后春笋般涌现,帮助WEB项目开发向 DOM 添加动作。
不过,最基本和最关键的部分是 CSS 中的 transition
。它是大多数前端开发人员学习的第一个动画工具,WEB 的交互动画大部分是由 CSS 来完成的。
前面介绍 keyframes
的使用《CSS交互动画指南之keyframes》,在本文中,将深入了解并学习更多关于 CSS 的动画之 transition
,文章涉及的代码示例效果可以点击查看动画效果。
基础知识
创建动画所需的主要角色是一些会发生变化的 CSS 属性,下面是一个鼠标悬停时移动的按钮示例,没有动画:
.btn { width: 80px; height: 80px; border-radius: 50%; border: none; margin: 15px; background-color: #6a5acd; place-content: center; color: white; text-align: center; } .btn:hover { transform: translateX(40px); }
当鼠标悬停在按钮上时,这个片段使用 :hover
伪类来指定一个额外的 CSS 声明,类似于 JavaScript 中的 onMouseEnter
事件。
为了向右移动元素,使用 transform: translateY(40px)
,虽然可以为此使用 margin-left,但 transform: translate
是一个更佳的方式。
从上面的效果来看,按钮的移动很生硬,下面就为按钮增加 transition
属性:
.transition { transition: transform 250ms; }
transition
属性值可以有多个值,但有两个是必需的:
- 动画属性的名称
- 动画的持续时间
如果动画是为多个属性设置的,用逗号分隔的列表作为transition
属性值:
.btn-2 { transition: transform 250ms, opacity 400ms; } .btn-2:hover { transform: scale(1.2); opacity: 0; }
transition
有一个特殊的值:all
,即为任何 CSS 属性的变化增加动画效果。
动画效果
当告诉一个元素从一个位置转换到另一个位置时,浏览器需要计算出每个 中间帧
应该过渡。
例如:假设从左到右移动一个元素,持续时间为 1 秒,流畅的动画应该以 60fps*
的速度切换,这意味着需要在开始和结束之间腾出 60 个单独的位置,就像电影胶片。如果按照均匀分布,每个浅色的圆圈代表一个帧动画。当圆圈从左向右移动时,这些是向用户显示的帧,如下:
在这个动画中,使用了一个线性定时函数,意味着元素以恒定的速度移动,图片中的圆圈每一帧的移动量都是相同的。
在 CSS 中有几种动画效果可供使用,通过 transition-timing-function
属性来指定:
.btn-3 { transition: transform 250ms; transition-timing-function: linear; /* 或者使用推荐方式 */ /* transition: transform 250ms linear;*/ }
ease-out
ease-out
的效果一头野牛冲了进来,但它耗尽了能量,到最后,就像一只昏昏欲睡的乌龟一样缓慢前行。
从图片效果可以看出前几帧的速度特别的块,以及它在最后变得迅速降低。
ease-in
eease-in
的效果正好与ease-out
相反,就有点洗衣机脱水,开始慢慢转动,然后快速加速。
ease-in-out
ease-in-out
是前面两个动画效果的组合:
ease
ease
与 ease-in-out
不同,它不是对称的,它的特点是有一个短暂的加速和很大的减速。
ease
是默认值,如果没有指定动画效果,则默认使用ease
。
自定义曲线
如果提供的内置选项不能满足需求,可以使用三次贝塞尔 timing
函数自定义缓动曲线。
.btn-4 { transition: transform 250ms cubic-bezier(0.1, 0.2, 0.3, 0.4); }
从上面语法可以看到所有值都是这个 cubic-bezier
函数的预设值,它需要4个数字,代表2个控制点。关于如何定义对应的预设值,推荐一个在线工具 cubic-bezier ,
调试出满意的动画曲线后,单击顶部的“复制”并将其粘贴到 CSS 中就可以实现相应的动画效果。
还可以从这个 Easing functions 缓动函数扩展集中进行选择,需要主要的是有些效果 CSS 的支持不是很好,需要根据实际情况选择。
动画演示
前面提到动画应该以60帧/秒
的速度运行。然而,当计算时,意识到这意味着浏览器只有16.6毫秒
来绘制每一帧,时间真的不多。作为参考,眨眼大约需要 100-300毫秒
。对于动画的速率,需要设置一个合理的值,要不然设备跟不上,帧会被丢弃。
在实践中,性能不佳通常会以可变帧率的形式出现,动画性能是一个非常深入和有趣的主题,这里不做详细介绍,但以下几点还是有必要了解一下:
- 有些CSS属性在制作动画时要比其他属性耗资源得多。例如,高度改变动画就是一个非常费资源的属性,因为它影响布局,当一个元素的高度缩小时,就会引起连锁反应,它的所有兄弟元素需要向上移动,以填补空间。
- 其他属性,如
background-color
,对于动画效果来说也有点影响性能,虽然它不会影响布局,但确实需要在每个动画帧上设置一个颜色。 transform
和opacity
,是非常推荐的动画效果,对性能影响不大。如果动画当前调整了width
或left
等属性,则可以通过transform
来进行转换(尽管并不总是可以达到完全相同的效果)- 请务必在网站/应用所针对的最低端设备上测试动画,为低端设备提供兼容的方案,如去掉动画效果。
硬件加速
根据最终用户浏览器和操作系统的不同,如下图的效果,就存在小缺陷:
仔细观察按钮字母,注意到它们在转换的开始和结束时出现了轻微的偏移,这是因为计算机的 CPU 和 GPU 之间的切换导致的。当使用 transform
和 opacity
为元素设置动画时,浏览器有时会尝试优化此动画效果。它不是在每一帧上光栅化像素,而是将所有内容作为纹理传输到 GPU,而 GPU 非常擅长进行这类基于纹理的转换,因此,得到了非常流畅、非常高性能的动画,这被称为硬件加速
。
硬件加速因此也叫 GPU 加速,是利用 GPU 进行渲染,减少 CPU 操作的一种优化方案。由于 GPU 中的 transform 等 CSS 属性不会触发重绘,所以能大大提高网页的性能。
可以通过添加以下 CSS 的 will-change
属性来设置硬件加速:
will-change
为web开发者提供了一种告知浏览器该元素会有哪些变化的方法,这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。
.btn-5 { will-change: transform; }
will-change
允许向浏览器声明将要为所选元素设置动画,并且应该针对这种情况进行优化,这样浏览器会一直让 GPU 处理这个元素。不再需要 CPU 和 GPU 之间的切换,不再有 卡入到位
的现象。
CSS 中的以下属性能触发硬件加速:
- transform
- opacity
- filter
- will-change
如果有一些元素不需要用到上述属性,但是需要触发硬件加速效果,可以使用一些小技巧来诱导浏览器开启硬件加速,如下:
.item { -webkit-transform: translateZ(0); -moz-transform: translateZ(0); -ms-transform: translateZ(0); -o-transform: translateZ(0); transform: translateZ(0); /**或者**/ transform: rotateZ(360deg); transform: translate3d(0, 0, 0); }
即使用
translateZ()
(或translate3d()
)这种hack方式(有时也称为null
变换hack
)来让浏览器对animation
或transform
行为使用硬件加速,通过向一个不会在三维空间中转换的元素添加简单的3D变换来实现硬件加速。
总结
前面介绍 keyframes
的使用《CSS交互动画指南之keyframes》,结合本文的 transition
,基本可以为前端项目增加相应的改善性的动画。