原文地址:CSS Animations vs the Web Animations API: A Case Study


May 03, 2017 css, javascript

上周我写了我如何使用CSS来制作bitsofcode logo动画。之后,有人建议我应该对CSS动画与Web Animations API做个对比,所以,这篇文章就是。

Web Animations API介绍

和上周一样,在开始之前我先对Web Animations API做下介绍。Web Animations API向开发者提供了通过JavaScript直接操作浏览器的动画引擎的方法。

创建动画

为了使用Web Animations API创建动画,我们需通过Element.animate()函数,该函数接受两个参数:keyframesoptions

element.animate(keyframes, options);

关键帧 keyframes

关键帧对象相当于动画中事件的时间轴,这里有两种方式来创建关键帧对象。为了列举这两种方式,这里以grow动画为例,该动画将会将元素的尺寸放大两倍。如下是通过CSS的@keyframes来声明:

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

第一种方式

关键帧的第一种方式是单个对象形式。对象的每个key代表了我们想要动画的CSS属性。每一个key的值都是一个由动画过程中的CSS值组成的数组。数组中的每个值表示动画时间轴中的一个点。

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

第二种方式

关键帧的第二种方式是写一个数组。数组中的每一个项表示动画时间轴中的一个点,在这个点上我们可以定义应用在该点上的每一条CSS属性与值。

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

默认情况下,时间轴上的每个点之间的空间是相等的。例如,如果在时间轴上我有5个点,则每个点之间的动画过渡时间都会是20%。

如果我们想自己改变过渡时间,可以使用上述中的第二种定义方式中的offset属性。该属性接受一个数字:0-1之间,表示该点动画应该在什么时候开始,例如,下面的CSS动画:

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

为了说明时间轴上的不相等的空间,我可以通过下面的方式书写:

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

选项 options

传递给animate()函数的第二个参数是一个带有动画选项信息的对象。如果我们使用CSS动画,这个对象允许我们指定应用于CSS动画的所有的属性。这里可以定义九个选项。

选项 描述
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 定义动画的循环从哪里开始,可以是0~1,0.5表示动画从中间开始运行

举个例子,让我们开始另一个grow动画。利用CSS动画,我们可以让动画持续3秒、无限循环、改变运行方向并且等待2秒后执行,如下是声明代码:

.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()函数可以将动画应用到该元素上,并且将关键帧(keyframes)选项(options)作为参数。

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动画一样,我从创建好的完整的动画中截取了一小段。下面是三个版本的对比:

创建时间轴

概括来说,如下是logo左侧部分的动画步骤(字母“bitso”中的o是开的,类似()。

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

基于上述步骤,这是我制作的左边部分的时间轴

下面是基于该时间轴利用Web Animation API创建的关键帧对象,具有时间轴上的每一步的样式规则。

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

设置参数

每一部分的参数都很简单,每个循环周期时长3秒,并且无限循环。

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

应用动画

使用Web Animation API来应用动画要比CSS动画有些繁琐。这是因为我只想当动画被hover或者focus的时候来运行。正如我所说的,默认情况下,Web Animation会在创建完之后立即运行。

为了解决这个问题,我不得不创建完动画后立即暂停,然后增加事件监听器,当事件触发,动画就可以播放或者暂停。另外,因为我要应用动画到每个字符上,那就必须要同时处理几个动画,下面是执行过程:

// 存储所有动画的数组
const animations = []; function playLogoAnimation() {
animations.map((animation) => animation.play())
} function pauseLogoAnimation() {
animations.map((animation) => {
animation.pause();
animation.currentTime = 0; // 重置动画为初始状态
})
} 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 … // 一旦创建完动画就立即停止
pauseLogoAnimation();
} createLogoAnimation(); // 时间监听器来开始或暂停动画
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 the Web Animation API

和其他一切一样,无论使用CSS还是JavaScript动画,取决于动画的细节。作为基本规则,CSS动画应该用在小型、和UI相关的动画,比如提示框(tooltip)。Web Animation API应该用作需要微调的更高级的效果。这就是我对这两种动画方式的比价。

性能

CSS vs JavaScript动画的性能会根据我们正在动画的属性而有很大的不同。通常,建议只对transform或者opacity属性进行动画,因为这些动画会在与浏览器主线程不同的线程上执行。

改变transform并不会触发任何几何形状的改变或渲染,性能会很好。这意味着操作可能在GPU的帮助下由合成器线程执行。

-- CSS Triggers

由于我的动画只用了transform属性,所以我不能看到这两种方案之间明显的性能差异。通过火狐的开发者工具,我测量了两个动画的帧率,获得了两个相同的帧率:60FPS,即使Main Thread Animation enabled为Off。

我无法找到更多的方式去测量两种方案的性能。如果你知道其他更好的方法,可以在下面留下评论。

开发者经验

在这个例子中,我个人发现CSS动画要比Web Animation API操作简单,更容易使用,主要是因为使用后者来播放暂停动画需要额外的工作。如果我是在做一个更复杂的动画比如一个游戏,Web Animation API会是一个一定要走的路。但是在这个例子中,我认为使用CSS动画更容易实现。

【翻译】CSS Animations VS the Web Animations API:案例学习的更多相关文章

  1. Web Animations API (JS动画利器)

    原文地址:→传送门 写在前面 之前学习了CSS animation/setTimeout/setInterval/requestAnimationFrame等,这些都可以用在某种场景下的小动画,也可以 ...

  2. Web Animations API & SVG & requestAnimationFrame

    Web Animations API WWAPI https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API https:/ ...

  3. abp学习(四)——根据入门教程(aspnetMVC Web API进一步学习)

    Introduction With AspNet MVC Web API EntityFramework and AngularJS 地址:https://aspnetboilerplate.com/ ...

  4. 关于Web Audio API的入门

    Web Audio API提供了一个简单强大的机制来实现控制web应用程序的音频内容.它允许你开发复杂的混音,音效,平移以及更多. 可以先看一下MDN的这篇文章<Web Audio API的运用 ...

  5. WEB音频API

    本文转载至 http://www.webhek.com/web-audio-api 很偶然的,在一个微信公众号里面,看到了这样的一篇文章. WEB音频API.作者分享技术的优良品质值得我们学习. 原文 ...

  6. H5的Web Audio Api

    概述 研究Web Audio Api的主要原因是:工作中需要在ios中实现声音的淡出效果,主要是通过setInterval来改audio标签的volume属性实现的,但是ios上面volume属性是只 ...

  7. Web Audio API之手把手教你用web api处理声音信号:可视化音乐demo

    1.Web Audio API 介绍 Web Audio API 提供了在Web上控制音频的一个非常有效通用的系统 ,这些通用系统通俗的讲就是我们可以利用Web Audio API提供的各种方法操作各 ...

  8. 使用Web存储API存取本地数据

    使用Web存储API TODO:本文由 赤石俊哉 翻译整理,您可以将本文自由地用于学习交流.如需用于其他用途请征得作者的同意. 原文链接:Using the Web Storage API - Moz ...

  9. HTML5权威指南--Web Storage,本地数据库,本地缓存API,Web Sockets API,Geolocation API(简要学习笔记二)

    1.Web Storage HTML5除了Canvas元素之外,还有一个非常重要的功能那就是客户端本地保存数据的Web Storage功能. 以前都是用cookies保存用户名等简单信息.   但是c ...

随机推荐

  1. SpringBoot Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.

    SpringBoot Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFact ...

  2. 用户使用VPS的12个常见问题

    1.VPS主机用户能否进行备份? VPS主机允许用户进行自主的备份,这个操作非常简单,是需要在用户控制面板点击备份按钮即可.同时还允许用户恢复到任何备份状态. 2.当某个VPS主机用户被攻击时,会不会 ...

  3. dedecms====phpcms 区别==[工作]

    {template "content","header"}{dede:include filename="head.htm"/} ----- ...

  4. mysql索引使用注意事项

    索引是快速搜索的关键.MySQL索引的建立对于MySQL的高效运行是很重要的.下面介绍几种常见的MySQL索引类型. 在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytabl ...

  5. 爬虫利器BeautifulSoup模块使用

    一.简介 BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式,同时应用场景也是非常丰富,你可以使用 ...

  6. MySQL 多版本并发控制(MVCC)

    可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁的操作,因此开销会很低.主要实现的是非阻塞的读操作,写操作也只是锁定必要的行.MVCC的实现是通过保存数据在某个时间点的快照来实现的,也 ...

  7. JS获取父、兄、子节点

    一.jQuery的父节点查找方法 $(selector).parent(selector):获取父节点 $(selector).parentNode:以node[]的形式存放父节点,如果没有父节点,则 ...

  8. bxslider使用教程

    bxSlider下载+参数说明 "bxSlider"就是一款响应式的幻灯片js插件 bxSlider特性 充分响应各种设备,适应各种屏幕: 支持多种滑动模式,水平.垂直以及淡入淡出 ...

  9. 【处理多服务器日志合并处理问题】多服务器的日志合并统计——apache日志的cronolog轮循

    转发:http://www.chedong.com/tech/rotate_merge_log.html   内容摘要:你完全不必耐心地看完下面的所有内容,因为结论无非以下2点:1 用 cronolo ...

  10. mybatis-databaseIdProvider多数据库支持

    <select id="selectPerson" parameterType="int" parameterMap="deprecated&q ...