CSS Animations vs Web Animations API
JavaScript提供了动画原生API,被称为Web Animations API。在这篇文章中我们称之为WAAPI。MDN有详细的文档,而且@Dan Wilson写了一个系列的文章来介绍WAAPI。
在这篇文章中,我们将比较WAAPI和CSS Animation之间的差异。
@Dan Wilson的系列文章,在W3cplus上提供相关的中文文档,另外小站也有其他关于WAAPI的相关介绍。
浏览器支持度
WAAPI有一个全面的和健壮的polyfill。即使浏览器不支持,你也可以在生产中使用(前提是需要引入WAAPI的polyfill)。
像往常一样,您可以使用Can I Use来检查浏览器对WAAPI的支持数据。然而,这并没有提供很好的WAAPI每个功能支持度的相关信息。下面有一个检查程序:
可以使用Firefox Nightly在没有使用polyfill情况下对WAAPI的所有功能支持度。
WAAPI基础
如果你曾经使用jQuery的.animate()
,那么WAAPI的基本语法看起来应该很熟悉。
var element = document.querySelector('.animate-me');
element.animate(keyframes, 1000);
animate
方法接受两个参数:keyframes
和duration
。与jQuery相比,它不仅被内置在浏览器,而且性能更好。
第一个参数keyframes
是一个对象数组。每个对象都是一个关键帧动画。下面是一个简单的示例:
var keyframes = [
{ opacity: 0 },
{ opacity: 1 }
];
第二个参数duration
指是我们希望动画持续多主。在上面的例子中是1000ms
。让我们来看一个更令人兴奋的例子。
使用WAAPI重新创建一个CSS的animista动画
animista这里有很多优秀的CSS动画,比如slide-in-blurred-top
这个入口动画。它看起来让人很舒服。
下面是CSS的keyframes
对应的代码:
0% {
transform: translateY(-1000px) scaleY(2.5) scaleX(.2);
transform-origin: 50% 0;
filter: blur(40px);
opacity: 0;
}
100% {
transform: translateY(0) scaleY(1) scaleX(1);
transform-origin: 50% 50%;
filter: blur(0);
opacity: 1;
}
上面的代码,使用WAAPI可以写成:
var keyframes = [
{
transform: 'translateY(-1000px) scaleY(2.5) scaleX(.2)',
transformOrigin: '50% 0', filter: 'blur(40px)', opacity: 0
},
{
transform: 'translateY(0) scaleY(1) scaleX(1)',
transformOrigin: '50% 50%',
filter: 'blur(0)',
opacity: 1
}
];
我们已经知道了把定义好的keyframes
运用到你想要的动画元素上是多么容易。
element.animate(keyframes, 700);
为了使用这个示例尽量的简单,我只指定了动画的持续时间。不过,.animate()
的第二个参数可以传递更多的选项。到少我们还应该指定个一个easing
(类似CSS动画中的animation-timing-function
)。下面这个示例显示了可以使用的完整列表项:
var options = {
iterations: Infinity, // 对应animation-iteration-count
iterationStart: 0,
delay: 0, // 对应animation-delay
endDelay: 0,
direction: 'alternate', // 对应animation-direction
duration: 700, // 对应animation-duration
fill: 'forwards', // 对应 animation-fill-mode
easing: 'ease-out', // 对应 animation-timing-function
}
element.animate(keyframes, options);
使用这些选项,我们的动画没有任何延迟就从头开始,并且在来回之间不间断的循环播放。
烦人的是,对于我们这些熟悉CSS动画的人来说,WAAPI的一些术语和CSS动画术语有些不同。从好的方面说,多了一些类型。
easing
相当于CSS的animation-timing-function
。iterations
相当于CSS的animation-iteration-count
。如果我们想让动画重复播放,使用Infinity
替代CSS动画中的infinite
。这有些令人会感到困惑,Infinity
不是一个复数。在JavaScript中Infinity
是一个关键词,而其他值是字符串。- 我们使用
ms
,而不是s
,对于写过JavaScript的同学来说这应该很熟悉。(你可能在CSS动画中使用过ms
,但估计很少人这么做)
让我们再来仔细看看其中的一个选项:iterationStart
。
当我第一次看到iterationStart
时我被难住了。为什么你想指定一个迭代(iteration)而不是减少迭代的数量?当你使用一个十进制数时,这个选项是非常有用的。例如,你可以将它设置为.5
,动画将开始进行到一半。如果你的迭代次数是1
的话,你要设置iterationStart
为.5
。动画将执行到一半动画就结束,而且动画会停留在开始和结束的中间。
值得注意的是,你还可以设置iterations
总数小于1
。例如:
var option = {
iterations: .5,
iterationStart: .5
}
一个动画可以从中间播放到最后。如果你想每个动画在各自的后面开始播放,但希望一个动画的结束和任何后续动画的开始之间有一个差距,那么endDelay: endDelay
是非常有用的。@Patrick Brosset的视频对这方面做了一个很形象的阐述。
Easing
easing
在动画中是非常重要的一个元素。WAAPI提供了两种不同的方式来设置easing
。一种是在keyframes
中设置,另一种是在参数对象中配置。
在CSS中,如果应用animation-timing-function:ease-in-out
,你会看到你的动画先加速,然后慢慢减速,直到动画停止。事实上,easing
适用于关键帧之间,而并不是整个动画。这样可以更颗粒度的控制动画的感觉。WAAPI也提供了这方面的能力。
var keyframes = [
{ opacity: 0, easing: 'ease-in' },
{ opacity: 0.5, easing: 'ease-out' },
{ opacity: 1 }
]
值得注意的是,不管是在CSS Animation还是在WAAPI中,你都不应该在最后一帧中设置easing
,因为这样是没有任何效果的。对于很多人而言,都会犯这个错误。有时候,为了更直观,给整个动画添加easing
。这对于CSS来说是不可能的,但是WAAPI实现了。
var options = {
duration: 1000,
easing: 'ease-in-out',
}
在下面的这个示例中,你将看到这两种方式的区别:
Ease vs. Linear
CSS Animation和WAAPI另一个区别是:CSS的animation-timing-function
默认值是ease
,而WAAPI的默认值是linear
。ease
实际上是ease-in-out
的另一个版本,如果你自己不想做任何的思考,那么这是一个不错的选择。同时,linear
是非常没劲的一个东东,它的速度一直保持不变,是一个匀速运动,看起来机械而又不自然。这也可能是被选为默认值的原因之一吧,因为它是最中立的选项。然而,使用WAAPI比使用CSS时,easing
变得更宽松,这也是重要的一点,以免你的动画看起来和机器人一样的乏味。
性能
WAAPI提供了CSS Animation 改进后的性能,尽管如此,这也并不意味着一个平滑的动画就没有性能问题。
我曾希望这个API的性能优化意味着我们可以避开使用will-change
和translateZ
之类的。最终它是可能的。然而,至少在当前浏览器实中使用这些属性仍然是有益的和必要的,特别是在处理性能问题(Jank)。
然而,如果你延迟你的动画,你不用担心使用will-change
。Web Animation规范的主要作者在社区中发表了一些建议,你感兴趣的话可以去深入阅读一下:
If you have a positive delay, you don't need
will-change
since the browser will layerize at the start of the delay and when the animation starts it will be ready to go.
WAAPI 与 CSS Animation
在JavaScript中,WAAPI提供了一个语法,可以实现一个样式。然而,他们不应该是竞争关系。如果我们决定使用CSS的animation
和transition
,其实也可以使用WAAPI来实现。
Animation对象
.animate()
方法不只是动画元素,它还返回一些东西。
var myAnimation = element.animate(keyframes, options);
如果看看控制台中的返回值,我们会看到一个动画对象。这给我们提供了各种各样的功能,其中一些是不言自明的,比如myAnimation.pause()
。这和CSS Animation中的animation-play-state
类似,但比WAAPI中的element.style.animationPlayState = "paused"
要更含糊。我们也可以使用myAnimation.reverse()
轻松让动画反转,也就是说,再一次使用WAAPI的语法可以轻松的实现CSS的animation-direction
属性。
然而,直到现在,在这个世界上没有比使用JavaScript操纵@keyframes
更为简单的事情。甚至像重新启动动画一样,正如@Chris Coyier说过还是需要一点技术的。使用WAAPI我们可以简单地使用myAnimation.play()
重放动画。比如从动画一开始,或者从中间开始播放动画。
我们甚至可以轻松的改变一个动画的速度。
myAnimation.playbackRate = 2; // speed it up
myAnimation.playbackRate = .4; // use a number less than one to slow it down
getAnimations()
该方法将返回使用WAAPI定义的任何动画以及任何CSS Animations或Transitions动画的一个数组。
// returns any animations or transitions applied to our element using CSS or WAAPI
element.getAnimations()
如果你感觉使用CSS定义和应用动画,getAnimations()
允许你使用API结合@keyframes
。如果你需要,仍然可以使用CSS让动画工作。其实这样的一个过程是非常的简单。
即使只有一个DOM元素使用一个动画,getAnimations()
也会返回一个数组。让我们抓住这一个动画对象。
var h2 = document.querySelector("h2");
var myCSSAnimation = h2.getAnimations()[0];
现在我们可以在CSS动画上使用WAAPI。
myCSSAnimation.playbackRate = 4;
myCSSAnimation.reverse();
Promises and Events
我们可以使用JavaScript代码:animationstart
、animationend
、 animationiteration
和transitionend
事件控制CSS动画。我们经常需要监听一个动画的结束,然后从DOM中移除元素。
在WAAPI中将再次使用动画的对象,相当于使用animationed
或transitionend
:
myAnimation.onfinish = function() {
element.remove();
}
WAAPI提供了事件和Promise。动画的.finished
事件会在一个动画结束的时候Promis会返回一个resolve
。这里有一个使用Promise的示例:
myAnimation.finished.then(() =>
element.remove())
让我们来看看Mozilla开发人员提供的一个简单示例。element.getAnimations()
返回一个动画对象数组。
Promise.all(document.getAnimations().map(animation =>
animation.finished)).then(function() {
// do something cool
})
未来
在这篇文章中提到的功能仅仅是一个开始。当前规范和现实还是有一定的距离。规范只是实现的一个开始。
本文根据@OLLIE WILLIAMS的《CSS Animations vs Web Animations API》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://css-tricks.com/css-animations-vs-web-animations-api
如需转载,烦请注明出处:https://www.fedev.cn/animation/css-animations-vs-web-animations-api.htmlNike LunarEpic Low Flyknit