Home > Article > Web Front-end > Web Animation 制作指南_html/css_WEB-ITnose
Web Animation (Web动画)在Web中的运用越来越广泛,但共制作(开发)并不是件易事。这里将主要总结一下有关于Web Animation制作相关的知识,以供给初次接触动画制作的同学有所帮助。
Web动画 的实现原理,是利用了人眼的“ 视觉暂留 ”现象,在短时间内连续播放数幅静止的画面,使肉眼因视觉残象产生错觉,而误以为画面在“ 动 ”。
Web动画中有几个主要的概念:
到目前为止,Web Animation实现方法主要有以下几种(大家觉见的):
在手淘中使用的动画主要有两大类:
对应的我们前端所要承载的就是Web Animation中的CSS Animation和JavaScript Animation。
CSS Animation是目前制作Web动画的一处主流方式,也是 W3C规范之一 。
CSS Animation实现原理较为简单,如果你曾经结束过Flash或者动手制作过GIF动画图,那么对CSS Animation能很好的理解。
CSS Animation制作Web动画分为三部分:
@keyframes 是CSS Animation中的最大功臣,可以在 @keyframes 集合中定义动画的效果,而这些效果其实就是对应的CSS规则集合。比如:
@keyframes anim-name{ 0% {background-position: 0 0;} 14.3% {background-position: -180px 0;} 28.6% {background-position: -360px 0;} 42.9% {background-position: -540px 0;} 57.2% {background-position: -720px 0;} 71.5% {background-position: -900px 0;} 85.8% {background-position: -1080px 0;} 100% {background-position: 0 0;}}
anim-name 就是通过 @keyframes 声明的动画名称,其集合中的百分数(比如 0% , 100% )就是动画的关键帧,关键帧对应的CSS规则就是实现动画的一些样式规则。
而其中较为麻烦的事情是如何确定关键帧的个数,以及怎么配合相应的动作。下面的工具可以帮助大家快速构建出所需的关键帧:
除此之外,也可以借用Adobe Edge Animation软件。有关于 @keyframes 使用的相关细节可以 阅读这篇文章 。
animation 属性主要用来调用 @keyframes 已声明好的动画。其主要包括以下几个属性:
animation 属性名 | 说明 |
---|---|
animation-name | 定义使用的动画名称,需要和 @keyframes 声明的动画名称一致 |
animation-duration | 用来指定元素播放动画所持续的时间长 |
animation-timing-function | 动画的播放方式 |
animation-delay | 指定元素动画开始播放的时间 |
animation-iteration-count | 指定元素播放动画的循环次数 |
animation-direction | 指定元素动画播放的方向,包括单向循环和双向循环 |
animation-play-state | 用来控制元素动画的播放状态 |
animation-fill-mode | 动画结束之后,关键帧值是否保留在结束状态时的值 |
其中 animation-name 、 animation-iteration-count 、 animation-direction 、 animation-play-state 和 animation-fill-mode 相对来说较为简单,在使用的时候根据其属性值的说明对号入座即可。较为复杂的是 animation-duration 和 animation-delay 的配合,特别是多个动画一起使用的时候。为了能很好的解决这方面的问题,除了经验、自己审美感之外,还可以借助Chrome的调式工具来进行调试。如下图所示:
在这个调试工具上,可以很好的帮助你控制好每个动画元素的 animation-duration 和 animation-delay 时间,而且能让它们配合的更好。
除了这两个属性之外 animation-timing-function 也相对复杂一些,其提供了一些关键值:
时间函数名称 | 说明 |
---|---|
ease | (逐渐变慢)默认值, ease 函数等同于贝塞尔曲线 cubic-bezier(0.25, 0.1, 0.25, 1.0) |
linear | (匀速), linear 函数等同于贝塞尔曲线 cubic-bezier(0.0, 0.0, 1.0, 1.0) |
ease-in | (加速), ease-in 函数等同于贝塞尔曲线 cubic-bezier(0.42, 0, 1.0, 1.0) |
ease-out | (减速), ease-out 函数等同于贝塞尔曲线 cubic-bezier(0, 0, 0.58, 1.0) |
ease-in-out | (加速然后减速), ease-in-out 函数等同于贝塞尔曲线 cubic-bezier(0.42, 0, 0.58, 1.0) |
cubic-bezier | 该值允许你去自定义一个时间曲线 |
steps() | 指定一个阶跃函数 |
cubic-bezier 是通过贝赛尔曲线来计算“转换”过程中的属性值。不过这个过程人肉处理也是非常麻烦的事情,在实际生产是可以使用在线工具( cubic-bezier )来帮你处理:
steps() 函数指定了一个阶跃函数,第一个参数指定了时间函数中的间隔数量(必须是正整数);第二个参数可选,接受 start 和 end 两个值,指定在每个间隔的起点或是终点发生阶跃变化,默认为 end 。
假设有一个 3s * 2 ( animation-iteration-count: 2;animation-duration: 3s; )的动画,我们分别对它应用 steps(3, start) 和 steps(3, end) ,做出阶跃函数曲线如下:
steps() 第一个参数将动画分割成三段。当指定跃点为 start 时,动画在每个计时周期的起点发生阶跃(即图中空心圆 → 实心圆)。由于第一次阶跃发生在第一个计时周期的起点处( 0s ),所以我们看到的第一步动画(初态)就为 1/3 的状态,因此在视觉上动画的过程为 1/3 → 2/3 → 1 。
在JavaScript中就类似于下面这样:
var animateAtStart = function (steps, duration) { var current = 0; var interval = duration / steps; var timer = function () { current++; applyStylesAtStep(current); if (current < steps) { setTimeout(timer, interval); } }; timer();};
当指定跃点为 end ,动画则在每个计时周期的终点发生阶跃(即图中空心圆 → 实心圆)。由于第一次阶跃发生在第一个计时周期结束时( 1s ),所以我们看到的初态为 0% 的状态;而在整个动画周期完成处( 3s ),虽然发生阶跃跳到了 100% 的状态,但同时动画结束,所以 100% 的状态不可视。因此在视觉上动画的过程为 0 → 1/3 → 2/3 (回忆一下数电里的异步清零,当所有输出端都为高电平的时候触发清零,所以全为高电平是暂态)。
在JavaScript中就类似于下面这样:
var animateAtEnd = function (steps, duration) { var current = 0; var interval = duration / steps; var timer = function () { applyStylesAtStep(current); current++; if (current < steps) { setTimeout(timer, interval); } }; timer();};
有了 steps() 也就有了Sprites动画。比如2015年年货节揭幕动画。
Web Animation API 称之为Web动画API,是一个新的JavaScript API。它致力于集合CSS3动画的性能、JavaScript的灵活、动画库的丰富等各家所长,将尽可能多的动画控制由原生浏览器实现,并添加许多CSS不具备的变量、控制以及或调的选项。
这里提供两个有关于Web Animation API的视频:
Alex Danilo在Google开发者大会介绍了Web动画API(WAAPI)。这是一个高水平的关于API的概述,关于它如何工作以及可以用于何处
Rachel Nabors 2015年在SFHTML5的演讲。除了对Web animation非常多的激情,还给非技术观众做了相当好的讲解。
WAAPI核心在于提供了 Element.animate() 方法,它会返回一个 AnimationPlayer ,其可以帮助我们做一些有趣的动画。 animation() 接受两个参数,一个是 KeyframeEffects 数组,一个是 AnimationEffectTimingProperties 选项。基本上第一个参数会映射到你放到CSS @keyframes 中的内容,第二个参数是你将在你的CSS规则中使用 animation-* 属性(或 animation 简写,像我前面用的那样)指定的内容。这里有个关键的好处是我们可以使用变量或重用先前定义的 KeyframeEffects ,而用CSS的话我们就会被限制只能使用我们先前定义的值。
对于每一个 KeyframeEffect ,我们把CSS中的百分比偏移量 offset 变成值为 0 到 1 的小数。它是 可选 的,如果你没有指定任何值,它们就会平均分布(所以如果你有三个,第一个的偏移量为 0 ,第二个的偏移量为 .5 ,第三个则为 1 )。你还可以指定一个 easing 属性,这和CSS中的 animation-timing-function 一样。 KeyframeEffect 中的其它属性也都是可以添加动画的属性。每个属性的值都应该和你在JavaScript中使用 element.style 指定的相匹配,即 opacity 的值应该是一个数字,而 transform 应该是字符串。
例如:
var player = document.getElementById('toAnimate').animate([], { duration: 700, //动画持续时长,毫秒(ms),相当于animation-duration easing: 'ease-in-out', //动画播放函数方式,相当于animation-timing-function delay: 10, //动画延迟播放时间,毫秒(ms),相当于animation-delay iterations: Infinity, //动画播放次数,相当于animation-iteration-count direction: 'alternate', //播放元素的方向,相当于animation-direction fill: 'forwards' //动画播放完之后,关键帧是否保留在结束状态,相当于animation-fill-mode});
调用 element.animate() ,会返回一个 AnimationPlayer 对象,然后动画开始播放。可以通过检查只读属性 playState 来查看当前动画的状态,它会返回如下五个字符串之一。通过调用下面的四种方法之一,还可以修改动画的当前状态:
var player = element.animate(/* ... */);console.log(player.playState); //"running"player.pause(); //"paused"player.play(); //"running"player.cancel(); //"idle"... 跳到初始状态player.finish(); //"finished"...跳到结束状态
除了 running 、 paused 、 idle 和 finished 这些状态,还有一个 pending 状态,定义了当一个播放或暂停任务被挂起时的状态。
通过读/写 playbackRate 属性来改变动画播放速度:
var player = element.animate(/* ... */);console.log(player.playbackRate); //1player.playbackRate = 2; // 两倍速度,可以加速也可以减速
使用CSS过渡,在过渡结束时,通常会触发一个事件。同样, AnimationPlayer 可以让你在动画完成,或者调用前面讨论的 finish() 方法时,指定一个 onfinish 函数。
注意: 根据规范的内容,设置了无限迭代次数的动画是没有结束的, playbackRate 的值也不可能为 0 。规范还要求调用一个已经存在的 oncancel 回调,以及使用除了这些回调之外的 Promise ,这应该会比较受欢迎(虽然目前还没有实现)。
每个 AnimationPlayer 都提供了两个读/写的时间相关的属性—— currentTime 和 startTime 。我们现在侧重讲解前者。
currentTime 返回当前动画的所在的毫秒数。最大值为 delay + (duration * iterations) ,当然,无限迭代的情况则没有最大值。
var player = element.animate([ {opacity: 1}, {opacity: 0}], { duration: 1000, delay: 500, iterations: 3});player.onfinish = function() { console.log(player.currentTime); // 3500};
动画的播放速率会影响时间轴进行的速度。如果你设置的播放率为 10 ,你的最大的 currentTime 保持不变,但是你会比时间轴快 10 倍。
因为 currentTime 是读/写属性,可以使用它来跳转到时间轴上的某个点。它还可以让我们同步两个动画。
可以给一个元素多次调用 animate() ,类似CSS中的多动画。例如,
使用的CSS:
#toAnimate { animation: pulse 1s, activate 3000ms, have-fun-with-it 2.5s;}@keyframes pulse { /* ... */}@keyframes activate { /* ... */}@keyframes have-fun-with-it { /* ... */}
使用WAAPI:
var animated = document.getElementById('toAnimate');var pulseKeyframes, //定义关键帧变量 activateKeyframes, haveFunKeyframes;var pulse = animated.animate(pulseKeyframes, 1000); //第二个参数是持续时间的有效简写var activate = animated.animate(activateKeyframes, 3000);var haveFunWithIt = animated.animate(haveFunKeyframes, 2500);
使用WAAPI,它可以创建三个 AnimationPlayer ,每个都可以暂停、播放、结束、取消,也可以通过时间轴或播放速率来进行控制。
KeyframeEffect 传入三个参数:要添加动画的元素、关键帧数组、时间函数 timing 选项。这个新对象基本上还是为单独动画绘制的蓝图。 它不用于启动动画,只能定义动画 。
var elem = document.getElementById('toAnimate');var timings = { duration: 1000, fill: 'both'}var keyframes = [ { opacity: 1 }, { opacity: 0 }];var effect = new KeyframeEffect(elem, keyframes, timings);
动画在过去的五年里发展得很好,因为强大的CSS支持以及JavaScript新增内容的提升。但是每一种实现动画的方法,都有其缺点和优点。
理想情况下,我们可以在浏览器级别打包尽可能多的动画控件放进去。这些库可以专注于提供新特性,还会自动更新。而 WAAPI 就是在试图做到这一点。它的目标是既有CSS的性能优势,又有JavaScript的优点和灵活性(还有SVG动画),然后把它赋给浏览器,使其工作得更好。
迪士尼经过基础工作练习的长时间累积,在 1981 年出版的 The Illusion of Life: Disney Animation 一书中发表了动画的十二个原则 ( 12 Principles of Animation ) 。这些原则描述了动画能怎样用于让观众相信自己沉浸在现实世界中。
了解这些原则,有助于你更好的完成Web动画效果。
这是物体存在质量且运动时质量保持不变的概念。当一个球在弹跳时,碰击到地面会变扁,恢复的时间会越来越短。创建对象的时候最有用的方法是参照实物,比如人、时钟和弹性球。
当它和网页元件一起工作时可能会忽略这个原则。DOM 对象不一定和实物相关,它会按需要在屏幕上缩放。例如,一个按钮会变大并变成一个信息框,或者错误信息会出现和消失。
运动不倾向于突然发生。在现实生活中,无论是一个球在掉到桌子前就开始滚动,或是一个人屈膝准备起跳,运动通常有着某种事先的累积。
我们能用它去让我们的过渡动画显得更逼真。预备动作可以是一个细微的反弹,帮人们理解什么对象将在屏幕中发生变化并留下痕迹。
例如,悬停在一个元件上时可以在它变大前稍微缩小,在初始列表中添加额外的条目来介绍其它条目的移除方法。
演出布局是确保对象在场景中得以聚焦,让场景中的其它对象和视觉在主动画发生的地方让位。这意味着要么把主动画放到突出的位置,要么模糊其它元件来让用户专注于看他们需要看的东西。
在网页方面,一种方法是用 model 覆盖在某些内容上。在现有页面添加一个遮罩并把那些主要关注的内容前置展示。
另一种方法是用动作。当很多对象在运动,你很难知道哪些值得关注。如果其它所有的动作停止,只留一个在运动,即使动得很微弱,这都可以让对象更容易被察觉。
还有一种方法是做一个晃动和闪烁的按钮来简单地建议用户比如他们可能要保存文档。屏幕保持静态,所以再细微的动作也会突显出来。
连续运动是绘制动画的每一帧,姿态对应是通常由一个 assistant 在定义一系列关键帧后填充间隔。
大多数网页动画用的是姿态对应:关键帧之间的过渡可以通过浏览器在每个关键帧之间的插入尽可能多的帧使动画流畅。
有一个例外是定时功能 step 。通过这个功能,浏览器 "steps" 可以把尽可能多的无序帧串清晰。你可以用这种方式绘制一系列图片并让浏览器按顺序显示出来,这开创了一种逐帧动画的风格。
事情并不总在同一时间发生。当一辆车从急刹到停下,车子会向前倾、有烟从轮胎冒出来、车里的司机继续向前冲。
这些细节是跟随和重叠动作的例子。它们在网页中能被用作帮助强调什么东西被停止,并不会被遗忘。例如一个条目可能在滑动时稍滑微远了些,但它自己会纠正到正确位置。
要创造一个重叠动作的感觉,我们可以让元件以稍微不同的速度移动到每处。这是一种在 iOS 系统的视窗 (View) 过渡中被运用得很好的方法。一些按钮和元件以不同速率运动,整体效果会比全部东西以相同速率运动要更逼真,并留出时间让访客去适当理解变化。
在网页方面,这可能意味着让过渡或动画的效果以不同速度来运行。
对象很少从静止状态一下子加速到最大速度,它们往往是逐步加速并在停止前变慢。没有加速和减速,动画感觉就像机器人。
在 CSS 方面,缓入缓出很容易被理解,在一个动画过程中计时功能是一种描述变化速率的方式。
使用计时功能,动画可以由慢加速 ( ease-in )、由快减速 ( ease-out ),或者用贝塞尔曲线做出更复杂的效果。
虽然对象是更逼真了,当它们遵循 缓入缓出 的时候它们很少沿直线运动——它们倾向于沿弧线运动。
我们有几种 CSS 的方式来实现弧线运动。一种是结合多个动画,比如在弹力球动画里,可以让球上下移动的同时让它右移,这时候球的显示效果就是沿弧线运动。
另外一种是旋转元件,我们可以设置一个在对象之外的原点来作为它的旋转中心。当我们旋转这个对象,它看上去就是沿着弧线运动。
虽然主动画正在发生,次要动作可以增强它的效果。这就好比某人在走路的时候摆动手臂和倾斜脑袋,或者弹性球弹起的时候扬起一些灰尘。
在网页方面,当主要焦点出现的时候就可以开始执行次要动作,比如拖拽一个条目到列表中间。
动画的时间节奏是需要多久去完成,它可以被用来让看起来很重的对象做很重的动画,或者用在添加字符的动画中。
这在网页上可能只要简单调整 animation-duration 或 transition-duration 值。
这很容易让动画消耗更多时间,但调整时间节奏可以帮动画的内容和交互方式变得更出众。
夸张手法在漫画中是最常用来为某些动作刻画吸引力和增加戏剧性的,比如一只狼试图把自己的喉咙张得更开地去咬东西可能会表现出更恐怖或者幽默的效果。
在网页中,对象可以通过上下滑动去强调和刻画吸引力,比如在填充表单的时候生动部分会比收缩和变淡的部分更突出。
当动画对象在三维中应该加倍注意确保它们遵循透视原则。因为人们习惯了生活在三维世界里,如果对象表现得与实际不符,会让它看起来很糟糕。
如今浏览器对三维变换的支持已经不错,这意味着我们可以在场景里旋转和放置三维对象,浏览器能自动控制它们的转换。
吸引力是艺术作品的特质,让我们与艺术家的想法连接起来。就像一个演员身上的魅力,是注重细节和动作相结合而打造吸引性的结果。
精心制作网页上的动画可以打造出吸引力,例如 Stripe 这样的公司用了大量的动画去增加它们结账流程的可靠性。
随着网页功能变得愈发复杂和精细,以及手机端H5发展中所遇到的硬件性能瓶颈,网页的运行时性能问题变得越来越突出。而用户对于网页运行时性能最直观的感受,莫过于UI操作的流畅程度。流畅或卡顿,爽或不爽,皆在于每个UI动画细节之间。
其中帧率能反映动画的流畅程度:
帧率能够量化动画的流畅程度,流畅的动画一般具备两个特点:
动画调优是有一定的策略与技巧的,下面提供一些参考意见:
Android设备优先调试:移动设备的硬件配置一般低于桌面设备,而移动端设备中,Android设备相比于iOS设备性能普遍较差,因此在Andorid设备下性能问题更加明显,幸运的是Android可以借助Chrome自带的远程调试工具方便调试动画性能(Android 4.0+),所以优先调试Android设备可以更早地发现问题,并能更方便地解决问题。
Chrome自带的帧率监测工具,用于侦听全局帧率,以及页面重绘耗时
Chrome Timeline,杀手级监测 & 调试工具
上面是Chrome浏览器下的监测与调试工具,如果你不太喜欢使用Chrome浏览器,可以使用JavaScript来做这方面的测试,比如 Stats.js ,它侦听全局或指定位置的帧率。
@awwwards-team整理了一份 Web Animation Infographics 。图中提供了有关于Web Animation各种资源:
在制作Web Animation时,有很多现成的资源可供参考,或者使用,推荐几个链接:
更多的资源集,可以点击这里查阅。
常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。中国Drupal社区核心成员之一。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《 图解CSS3:核心技术与案例实战 》。