现代 CSS

CSS Animations vs Web Animations API

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

上周,我写了一篇关于如何使用CSS制作bitsofcode logo的动画效果。之后收到一些建议,尝试比较一下CSS动画和Web Animations API。所以今天写了这篇文章。

Web Animations API简介

和上周一样,我开始介绍Web Animations API。 Web Animations API为开发人员提供了一种方式,使用JavaScript可以直接操作浏览器的动画引擎。

如果你没有从示接触过Web Animations API的话,这篇文章是一篇很好的入门课程。除此之外,在站上已经有很多相关的教程,感兴趣的同学,可以点击这里进行阅读

创建一个动画

使用Web Animations API创建一个动画,可以使用Element.animate()函数,这个函数接受两个参数keyframesoptions

element.animate(keyframes, options);  

keyframes

keyframes对象代表动画事件的时间线(Timeline)。有两种方法来写这个对象。为了说明他,我们来创建一个grow动画,这个动画的效果是把元素放大两倍。使用CSS的@keyframes可以这样写:

@keyframes grow {
    0% {
        transform: none;
    }
    100% {
        transform: scale(2);
    }
}

第一种写keyframes的方法是把它声明成一个单独的对象。对象中的每个键(key)代表我们想要动画的CSS属性。每个键的值(values)是一个数组,数组里的值是我们想要动画的CSS属性值。数组中的每个值代表动画时间轴中每一个点的。

const growKeyframes = {  
    transform: ['none', 'scale(2)'];
}

第二种写keyframes的方法是把它写成一个数组。数组中的每一项代表时间线上的一个点,数组中的每个值是想要动画的CSS的属性和值。

const growKeyframes = [  
    { transform: 'none' },
    { transform: 'scale(2)' }
]

默认情况下,每个点在时间轴上是等距的。例如,如果我们的时间轴上有五个点,那么每个点之间的动画过渡时间都是同样的,都是20%

如果我们想改变时间,给keyframes写第二个值,给这个值设置offset属性,这个属性接受01之间的数字,这个数值就是代表CSS的@keyframes中的百分比值:

@keyframes alteredGrow {
    0% { transform: none; }
    10% { transform: scale(1.5); }
    30% { transform: scale(1.9); }
    100% { transform: scale(2); }
}

上面CSS的@keyframes我们可以写成:

const alteredGrowKeyframes = [  
    { transform: 'none' },
    { transform: 'scale(1.5)', offset: 0.1 }
    { transform: 'scale(1.9)', offset: 0.3 }
    { transform: 'scale(2)' }
]

options

animate()函数的第二个参数是一个对象,该对象允许我们指定所有适用于动画CSS属性。总共有九个选项:

  • id:一个独特的参考动画(设置或者获取动画的id名)
  • delay:指定延迟播放动画时间,对应CSS的animation-delay属性
  • duration:指定动画持续播放时间,对应CSS的animation-duration属性
  • iterations:指定动画循环播放次数,对应CSS的animation-iteration-count属性
  • direction:指定在时间轴哪个方向运行动画,对应CSS的animation-direction属性
  • easing:指定动画之间的转换方式,对应CSS的animation-timing-function属性
  • fill:指定元素动画开始和结束值,对应CSS的animation-fill-mode属性
  • endDelay:指定一个时间延迟后的动画
  • iterationStart:指定第n次动画播放的开始时间

例如,让我们来调用alteredGrow动画,使用CSS的动画属性来控制,比如动画播放持续3s,延迟2s开始播放,动画的播放方向alternate,并且无限次播放:

.animated-element {
    animation-name: alteredGrow;
    animation-duration: 3s;
    animation-iteration-count: infinite;
    animation-direction: alternate;
    animation-delay: 2s;
}

使用Web Animations API,我们可以指定同样的参数:

const alteredGrowOptions = {  
    duration: 3000,
    iterations: Infinity,
    direction: 'alternate',
    delay: 2000
}

使用动画

在需要运用动画的元素上调用animate()函数,并且给它指定keyframesoptions参数:

const element = document.querySelector('.animated-element');  
element.animate(alteredGrowKeyframes, alteredGrowOptions);  

一旦函数被调用,动画就会自动播放。然后我们可以通过play()pause()方法来控制动画的开始和停止:

const element = document.querySelector('.animated-element');  
const myAnimation = element.animate(alteredGrowKeyframes, alteredGrowOptions);

myAnimation.pause();  
myAnimation.play();  

浏览器兼容性

bitsofcode Logo动画效果

下面视频录制了使用CSS动画制作的bitsofcode Logo的动画效果。

创建Timeline

回顾一下,Logo中动画步骤(Logo从o字分开,"bitso"):

  • 向左移动
  • 回到中间
  • 停在中间(等右边部分向右移动)
  • 移到左边
  • 旋转
  • 慢慢增加旋转
  • 回到不旋转位置
  • 回到中间

基于这些步骤,左边部分可以创建一个Timeline:

基于这个时间线,Web动画中的keyframes对象每步对应的样式如下:

const logoSectionLeftKeyframes = [  
    { transform: 'none' },
    { offset: 0.125, transform: 'translateX(-15px)' },
    { offset: 0.25, transform: 'none' },
    { offset: 0.5, transform: 'none' },
    { offset: 0.625, transform: 'translateX(-15px)' },
    { offset: 0.67, transform: 'translateX(-15px) rotate(-10deg)' },
    { offset: 0.72, transform: 'translateX(-15px) rotate(-10deg)' },
    { offset: 0.82, transform: 'translateX(-15px) rotate(-15deg)' },
    { offset: 0.875, transform: 'translateX(-15px)' },
    { transform: 'none' }
];

因为需要使用offset属性,所以我决定使用数组的格式来定义keyframes

设置参数

参数设置很简单,动画持续播放的时间是3s,并且是无限次数的播放。

const logoSectionOptions = {  
    duration: 3000,
    iterations: Infinity
};

运用动画

Web Animation API应用动画要比CSS Animation更繁琐。主要是因为Logo在鼠标悬浮或得到焦点时才有动画效果。正如我提到的,默认情况下,Web动画动行就创建了动画。

为了解决这一问题,我必须先创建动画,然后通过eventListeners来监听动画的播放或暂停。此外,由于这个动画应用于每个字母,我不得不一次处理多个动画。下面的代码就是如何让动画执行:

// Array to store all animations
const animations = [];

function playLogoAnimation() {  
    animations.map((animation) => animation.play())
}

function pauseLogoAnimation() {  
    animations.map((animation) => {
        animation.pause();
        animation.currentTime = 0; // Reset animation to start state
    })
}

function createLogoAnimation() {  
    const logoSectionLeftEls = Array.from( document.querySelectorAll('.logo-section-left') );
    logoSectionLeftEls.forEach((el) => animations.push(el.animate(logoSectionLeftKeyframes, logoSectionTiming)))

    // Animation for middle and right sections here …

    // Immediately pause animation once created
    pauseLogoAnimation();
}

createLogoAnimation();

// Event listeners to play or pause animation
const siteTitleLink = document.querySelector('.site__title a');  
siteTitleLink.addEventListener('mouseover', playLogoAnimation);  
siteTitleLink.addEventListener('mouseout', pauseLogoAnimation);  
siteTitleLink.addEventListener('keyup', (e) => {  
    if ( e.keyCode === 9 ) playLogoAnimation();
});
siteTitleLink.addEventListener('keydown', (e) => {  
    if ( e.keyCode === 9 ) pauseLogoAnimation();
});

最后整个效果如下:

CSS Animations VS Web Animation API

和其他事情一样,肯定会被问及是否使用CSS或JavaScript动画,很大程度上取决于动画的细节。作为一般规则,CSS动画应用小的场景,与UI相关的动画,比如提示信息(tooltip)。Web Animation API应该留给更高级的效果。这就是我认为选择CSS动画或JavaScript动画的一般规则。

性能

CSS和JavaScript动画的性能主要取决于动画属性。一般来说,我建议只在动画中使用transformopacity属性,因为这些动画可以在不同的线程上执行,也就是在浏览器的主线程上执行。

改变transform不会触发任何几何形状的变化或重绘,这是非常好的一点。这意味着这些操作可能可以人工启动GPU——CSS Triggers

自从我的动画只使用transform属性,我在这两个方法之间无法看到任何显著的性能差异。使用Firefox的DevTools,可以测量两个动的帧率,他们是完全相同,都在60FPS,即使启用了主线程的动画。

我没办未能找到更多的方法来衡量这两个方法之间的性能。如果你知道任何更好的方法,请在下面的评论中与我们分享。

开发经验

在这种情况下,我个人发现CSS动画比使用Web Animation API更容易,这主要是因为后者额外的工作主要花在了动画的播放或暂停。如果要做一个更为复杂的动画,例如游戏,Web Animation API肯定是更好,然而,对于这个示例,我认为CSS动画是更简单的。

本文根据@Ire Aderinokun的《CSS Animations vs the Web Animations API: A Case Study》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://bitsofco.de/css-animations-vs-the-web-animations-api/

大漠

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

如需转载,烦请注明出处:http://www.w3cplus.com/animation/css-animations-vs-the-web-animations-api.htmlOff White X Max 97

返回顶部