基于关键帧的CSS3动画

简介

静态网站普遍存在的时代已经是很久以前的事了。 随着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动画演示。 下面的图片是这个应用程序的截图。

 

 

Fig 1 应用程序截图 

 

在屏幕的中间有一个字符,用来对用户的操作做出反应。 当用户点击角落的黄色圆圈时,中间的字符就会跑到对应的圆圈中,并且在移动过程中会有相应的动画效果。 在屏幕上方的中间,有一个黑色的圆圈,当动画启动时,它就会变绿。 另外,字符不断地动态变化是用帧序列动画实现的。 我们将讲解这些动画特性是怎样实现的。

我们使用jQuery库的2.0.0版本,简化了应用程序和用户的交互。 这是我们唯一使用的外部库。

帧序列动画

在屏幕中间的蓝色字符是帧序列动画。 我们需要准备子画面图片,每个动画帧从左到右按顺序排放。 下面的图片展示了这些子图片的效果。

 

 

Fig 2 帧序列子画面图片 

 

从上面的图片可以看到,由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等。

文件附件: