基于关键帧的CSS3动画
PUBLISHED
简介
静态网站普遍存在的时代已经是很久以前的事了。 随着Flash的引入,网页开始变得越来越形象,并且具有一定的互动性。 然而,Flash渐渐的被HTML5所取代,因为HTML5与Flash的功能很接近,并且HTML5是基于公开的标准。 这是Web和移动应用程序的未来。 为了让开发者能开发关键帧动画功能,W3C引入了CSS3动画。 CSS3可以绘制动态的HTML元素,特别是元素的CSS3属性。 下面我就将介绍CSS3动画。
CSS3动画规范还在指定中,从2009年3月20日开始,Tizen就开始投入到其版本的制定中。 因此,你必须在每个标识符前写上“webkit”前缀。
关键帧
简单的动画可以使用CSS3的Transitions属性来创建。 Transiton只允许改变单独动画的CSS3属性值。 如果你想通过多次改变属性值来创建复杂的动画,那就需要用到关键帧技术。关键帧是W3C CSS3动画规范的一部分。 在CSS3中,一个关键帧其实就是在一段给定时间内的一堆属性值的集合。 我们使用@-webkit-keyframes关键字(只要规范还在起草中,我们就必须使用webkit前缀)来声明一个关键帧,并指定动画的名字。 然后在花括号之间,我们声明动画的关键帧。 每个关键帧都包含了一个属性列表,这些属性的值会随着时间发生变化。 请看下面的代码。
@-webkit-keyframes animation-name { from { width: 100px; } to { width: 200px; } }
在这个实例代码中,定义了两个帧,一个是动画起始帧“from”,一个是动画结束帧“to”。 这个定义使得元素的宽度从100pixels到200pixels之间动态变化。 注意,我们给这个动画设置一个名字”animation-name“,稍后将会用到它。
只有两个关键帧的动画等同于使用CSS3的Transitions属性。 我们还可以添加更多的关键帧。 我们通过使用动画持续时间的百分值来定义它们。 当我们在4秒动画中以动画长度50%创建一个关键帧,那50%就意味着动画开始2秒后,元素的宽度就会到相应的值。 这从下面的代码中就能看的很明白。
@-webkit-keyframes animation-name { // Let's assume that animation lasts 4 seconds. 0% { // After 0 seconds. width: 100px; } 50% { // After 2 seconds. width: 300px; } 100% { // After 4 seconds. width: 200px; } }
正如你能看到的,我们已经将“from”关键帧的百分比替换为0%,“to”关键帧的百分比替换为100%。 关键帧的定义顺序的改变是不会影响动画效果的。 也可以通过一组用逗号分隔的百分比值定义多个关键帧。
@-webkit-keyframes animation-name { // Let's assume that animation lasts 4 seconds. 0%, 75% { // After 0 seconds and after 3 seconds. width: 100px; } 100% { // After 4 seconds. width: 200px; } 50% { // After 2 seconds - different order doesn't affect animation. width: 300px; } }
我们也可以多次定义同一个关键帧,那新的关键帧就会覆盖前面的老的关键帧。 这是很有用的,当我们在一个关键帧集合中定义多个关键帧,我们可能只想改变某个关键帧的某些值,而其他的值不需要变化。
@-webkit-keyframes animation-name { // Let's assume that animation lasts 4 seconds. 0%, 50% { // After 0 seconds and after 2 seconds. width: 100px; height: 100px; } 50% { // After 2 seconds. height: 400px; // We overwrite height value. } 100% { // After 4 seconds. width: 200px; height: 200px; } }
我们可以设置哪些属性?
我们只能设置中间值能被计算出来的CSS属性。 它们是相同的值,与CSS3 Transitions文章相关的工作讨论中提到的CSS3 Transitions属性使用这些值,
运行动画
在上面的例子中,我们命名关键帧的名字为“animation-name”。 现在我们要用这个名字来运行一个动画。 首先,我们要用-webkit-animation-name属性来指定要运行的动画名称。 其次,我们需要有动画的运行时间。 我们使用-webkit-animation-time属性来指定动画的运行时间。 时间的单位可以是秒或者毫秒。 要让动画作为一个HTML元素运行,我们只需要设置者两个属性就可以了。
div { -webkit-animation-name: animation-name; -webkit-animation-time: 4s; }
我们还可以设置其他的属性来控制动画。 下面我们将一一描述。
-webkit-animation-timing-function
这个属性指定了帧与帧之间的动画属性的变化形式。 这个属性的值可以是以下几个值:linear,ease,ease-in,ease-out,ease-in-out,steps。 这些属性与CSS3 Transitions中使用的属性一样,想了解Transition属性,可以看相关的CSS3 Transition的文章。 这个属性的默认值是“ease”。 此外,这个属性不仅仅只是用于整个动画,它也可以用于单个关键帧内部,用来控制属性值变化的快慢。
@-webkit-keyframes animation-name { 0% { width: 100px; -webkit-animation-timing-function: ease; } 50% { width: 300px; -webkit-animation-timing-function: linear; } 100% { width: 200px; -webkit-animation-timing-function: ease-in; } }
我们要重点讨论一下“step”定时功能。 这是一个强大的功能,它可以用来创建帧顺序动画。 它能立即改变每个关键帧的属性值,而不是平稳的改变兄弟帧的属性值。 子动画已经准备好后,我们可以通过即时步骤移动背景实现一个帧顺序动画。 最后一章讨论样例程序时,我们将详细讨论这个功能。
-webkit-animation-iteration-count
我们通过设置这个属性来控制动画重复播放的次数。 这个属性的默认值是1。 我们可以设置该属性值为任意的整数或者无穷大,让动画一直重复播放下去。
-webkit-animation-direction
这个属性控制动画的播放方向。 该属性可以设置为下面的值:
- normal - 仅仅将动画东头到尾播放一遍,
- reverse - 将动画从尾到头播放一遍,
- alternate - 将动画从头到尾播放一遍,然后再从尾到头播放一遍(-webkit-animation-iteration-count属性要设置为2才能看到效果),
- alternate-reverse - 是reverse和alternate属性的集合, 这个属性将是动画返回来回的播放,并最终停留在第一个关键帧上。
-webkit-animation-play-state
感谢这个属性,我们能使动画暂停。 对于一些类选择器,我们可以将这个属性设置为“paused”,点击这个动画后,在一些动画元素上触发这个类。 请看下面的代码。 通过在DIV动画中添加和删除“pause”类,我们可以知道动画是不是在播放。
@-webkit-keyframes 'animation-name' { from { width: 100px; } to { width: 200px; } } div { height: 100px; background: black; -webkit-animation: 2s 'animation-name' infinite; } .pause { -webkit-animation-play-state: paused; }
-webkit-animation-delay
通过设置这个属性,我们可以将动画延迟播放。 这个属性值可以是秒或者是毫秒,默认值是0秒。
-webkit-animation-fill-mode
这个属性决定了在动画播放结束之后,哪些值需要被设置。 它包含下面一些值:
- none - 元素回退到初始状态(动画开始之前的状态),
- forwards - 最后一个关键帧的属性值将会在动画播放结束后设置给元素,
- backwards - 在动画播放之前,第一个关键帧的属性值将会被设置给元素(这个只有在没有设置动画延迟播放时才能起效),
- both - 相当于forwards和backwards规则的集合。
-webkit-animation
这是前面所有属性的简化版。 我们一个一个写出属性,用空格隔开。 属性顺序如下:single-animation-name,time,single-animation-timing-function,time,single-animation-iteration-count,single-animation-direction,single-animation-fill-mode,single-animation-play-state。 上面的顺序不是强制的。 想了解详细信息,请参考相关的文档。
动画事件
CSS3动画提供了3种动画事件:animationStart,animationInteration和animationEnd。 每个事件都需要添加“webkit”前缀。 webkitAnimationStart事件在动画开始时触发,webkitAnimationIteration事件在动画迭代播放完成后触发,webkitAnimationEnd在动画结束后触发。 每个事件都会有相应的事件回调函数,并把事件对象作为回调函数的参数。 事件对象有一些有用的属性。
- animationName - 动画事件对应的动画名称,
- elapsedTime - 动画开始后所消耗的时间。
示例应用程序
这个例子是一个简单的CSS3动画演示。 下面的图片是这个应用程序的截图。
在屏幕的中间有一个字符,用来对用户的操作做出反应。 当用户点击角落的黄色圆圈时,中间的字符就会跑到对应的圆圈中,并且在移动过程中会有相应的动画效果。 在屏幕上方的中间,有一个黑色的圆圈,当动画启动时,它就会变绿。 另外,字符不断地动态变化是用帧序列动画实现的。 我们将讲解这些动画特性是怎样实现的。
我们使用jQuery库的2.0.0版本,简化了应用程序和用户的交互。 这是我们唯一使用的外部库。
帧序列动画
在屏幕中间的蓝色字符是帧序列动画。 我们需要准备子画面图片,每个动画帧从左到右按顺序排放。 下面的图片展示了这些子图片的效果。
从上面的图片可以看到,由10个帧图片组成的序列帧来展示动画效果。 这个图片是DIV元素的背景图片,DIV元素用“sprite”类来表示。 让我们检查这个类是什么样子的。
.sprite { position: absolute; left: 360px; top: 640px; margin-left: -200px; margin-top: -225px; width: 400px; height: 450px; background-image: url('../images/sprite.png'); background-position: 0px 0px; -webkit-animation: sprite .8s steps(10) infinite; }
我们设置元素的大小为400px X 450px。 子画面图片的宽度是4000像素,所以就给出了10个帧。 背景被移动到(0,0)位置,也就是动画的第一个帧。 我们必须将背景位置移动到左边来产生动画效果。 在“sprite”类的最后一行,我们使用“-webkit-animation”属性,这个属性待会儿在讨论。 设置动画时间属性为0.8秒,定时属性设置为“step”,步数设置为10。 这就创建了一个10帧的动画,每个帧的播放的时间间隔为0.08秒。 因为我们想一直播放这个动画,所以将“-webkit-animation”设置为“infinite”。
“sprite”动画的定义可以更加简单。 背景位置的变化范围是(0px,0px)到(-4000px,0px)。 每走一步,背景就向左移动400像素。
@-webkit-keyframes sprite { from { background-position: 0px 0px; } to { background-position: -4000px 0px; } }
移动字符
当点击黄色圆圈时,字符就会移动到点击的圆圈上。 移动字符的动画的类型取决于我们所点击的那个圆圈。 所以我们就为4个类,对于每个点击的圆圈,这4个类带有不同的动画。 当我们点击其中的一个圆圈时,对应的类就会应用到我们的字符上。 每个类动画的持续时间为1秒,并且延迟200毫秒开始播放。 定时功能设置为ease。 字符先移动到对应的圆圈,然后会再回到屏幕中间,所以我们将迭代数设置为2,动画方向设置为alternate。
.animation-1 { -webkit-animation: animation-1 1s ease 200ms 2 alternate; } .animation-2 { -webkit-animation: animation-2 1s ease 200ms 2 alternate; } .animation-3 { -webkit-animation: animation-3 1s ease 200ms 2 alternate; } .animation-4 { -webkit-animation: animation-4 1s ease 200ms 2 alternate; }
我们来看看动画的关键帧定义。
@-webkit-keyframes animation-1 { 50% { left: 100px; opacity: 0.25; -webkit-transform: scale(0.5); } 100% { left: 100px; top: 100px; } } @-webkit-keyframes animation-2 { 50% { top: 100px; } 100% { left: 620px; top: 100px; -webkit-transform: rotate(360deg) scale(0.6); -webkit-filter: saturate(0%); } } @-webkit-keyframes animation-3 { 50% { top: 1180px; } 100% { left: 620px; top: 1180px; -webkit-transform: scale(0.4, 0.4) ro-tate(720deg); -webkit-filter: hue-rotate(-80deg); } } @-webkit-keyframes animation-4 { 50% { top: 1180px; } 100% { left: 100px; top: 1180px; -webkit-transform: scale(0.4, 0.4) skewX(-30deg); } }
每个动画包含了两个关键帧。 我们使用了多个CSS属性来产生动画效果。 我们在位置,旋转,缩放,色度,饱和度和扭曲度上添加了动画效果。 旋转,缩放和扭曲度用CSS3 Transitions属性来控制,有关它们的内容可以阅读官方说明。 色度和饱和度用CSS3的Filters属性来控制,你可以阅读这里关于它们的内容。
现在来看看用户的动作是怎样影响到字符的。
addAnimation = function (id) { if (id >= 1 && id <= 4) { sprite.addClass('animation-' + id); } }; $('.point').on('click', function (e) { var point; point = $(this); if(!sprite.is('.animation-1, .animation-2, .animation-3, .animation-4')) { addAnimation(parseInt(point.attr('id').replace('point-', ''), 10)); } e.stopPropagation(); e.preventDefault(); });
我们给所有的黄色圆圈绑定了点击事件的回调函数。 首先,检查是否有动画分配给了字符。 如果没有任何的动画分配,那我们就通过点击圆圈来给字符添加动画。 用“addAnimation()”函数来实现这一功能。 这个函数指定了需要给字符添加的动画的数量。 “sprite”对象拥有字符的DIV元素。
sprite = $('#sprite');
动画事件
最后来讨论一下怎样在动画播放过程中回退播放进度。 当动画运行起来后,屏幕上方中间的黑圆圈会变成绿色。 这是在不考虑延迟的情况下。如果考虑延迟,在延迟时间到之后,黑圈就会变绿,并且会产生相应的动画效果。
首先,我们要是用jQuery函数“on()”给动画启动和动画结束事件绑定回调函数。
sprite.on({ 'webkitAnimationStart': function (e) { if (e.originalEvent.animationName !== 'sprite') { indicator.addClass('start'); } }, 'webkitAnimationEnd': function (e) { if (e.originalEvent.animationName !== 'sprite') { removeAnimation(e.originalEvent.animationName); indicator.removeClass('start'); } } });
首先我们要检查事件调用的动画名称是不是“sprite”。 当动画启动时,要给标示添加“start”类,动画结束时,就要删除那些类。 我们用“removeAnimation()”函数来删除字符上的动画类,这个函数的参数是动画的名称。 如果不指定动画名称,这个函数将删除所有的动画。
removeAnimation = function (name) { sprite.removeClass(typeof name !== 'undefined' ? name : 'animation-1 anima-tion-2 animation-3 animation-4'); };
总结
我希望这篇文章能帮助你理解CSS3动画的基础知识。 你现在应该能创建一些简单的动画。 当然,创建复杂的动画效果也可以使用一些虚拟的编辑器,这些编辑器使用起来更加的方便简洁,不用再一行一行的写关键帧了。 还有一些其他的工具能帮助你制做CSS3动画,如Sencha Animation,Motion Composer等。