前端开发者学堂 - fedev.cn

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方法接受两个参数:keyframesduration。与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的默认值是linearease实际上是ease-in-out的另一个版本,如果你自己不想做任何的思考,那么这是一个不错的选择。同时,linear是非常没劲的一个东东,它的速度一直保持不变,是一个匀速运动,看起来机械而又不自然。这也可能是被选为默认值的原因之一吧,因为它是最中立的选项。然而,使用WAAPI比使用CSS时,easing变得更宽松,这也是重要的一点,以免你的动画看起来和机器人一样的乏味。

性能

WAAPI提供了CSS Animation 改进后的性能,尽管如此,这也并不意味着一个平滑的动画就没有性能问题。

我曾希望这个API的性能优化意味着我们可以避开使用will-changetranslateZ之类的。最终它是可能的。然而,至少在当前浏览器实中使用这些属性仍然是有益的和必要的,特别是在处理性能问题(Jank)。

然而,如果你延迟你的动画,你不用担心使用will-changeWeb 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的animationtransition,其实也可以使用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代码:animationstartanimationendanimationiterationtransitionend事件控制CSS动画。我们经常需要监听一个动画的结束,然后从DOM中移除元素。

在WAAPI中将再次使用动画的对象,相当于使用animationedtransitionend

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

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/animation/css-animations-vs-web-animations-api.htmlNike LunarEpic Low Flyknit