thanks kirupa


在HTML中动画实现的三种的方式之一是众所周知CSS animations。CSS animations是非常简单的。你能通过控制动画CSS属性来影响元素。它可以让你做出很酷的事比如元素移动、元素淡入淡出、改变元素颜色。

首先让我们看一个例子,让下面的云彩缓慢的上下飘动:

在本篇中,你将学习所有CSS animations,不仅仅是让云朵移动,还有其它更酷更有用的事情。你将会学习通过animation属性怎样定义一个CSS动画,怎么添加关键帧,以及如果调整各种动画相关的属性,这才是你所想要的。

Onwards!


Creating a Simple Animation

学习动画最简单的的方式,就是亲自动手实验, 然后再学习它的工作机制。那么来创建一个HTML文档,写HTML和CSS代码吧:

<!DOCTYPE html>
<html lang="en-us">

<head>
<meta charset="utf-8">
<title>Bouncing Clouds</title>
<script src="http://www.kirupa.com/js/prefixfree.min.js"></script>

<style>
#mainContent {
    background-color: #A2BFCE;
    border-radius: 4px;
    padding: 10px;
    width: 600px;
    height: 300px;
    overflow: hidden;
}
.cloud {
    position: absolute;
}
#bigcloud {
    margin-left: 100px;
    margin-top: 15px;
}
</style>
</head>

<body>
    <div id="mainContent">
    <img id="bigcloud" alt="#" class="cloud" height="154" src="http://www.kirupa.com/images/bigCloud.png" width="238">
    </div>
</body>

</html>

如果预览上面代码,和刚才那个例子对比,这是一个不令人兴奋的版本。你所看到的是单一的、静止不动的云朵:

Animation Img

让我们来继续添加animation属性来改变这无趣的状态吧。添加CSS animation只有两步,第一步设置animation属性,第二步精确的定义动画的关键帧。

#bigcloud上添加以下高亮行的属性:

#bigcloud {
    animation: bobble 2s infinite;/*highlight line*/
    margin-left: 100px;
    margin-top: 15px;
}

上面高亮的那行的细节是什么现在并不重要,稍后我们再来关注它。让我们先添加关键帧。添加@keyframes样式属性:

@keyframes bobble {
    0% {
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
    50% {
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }
    100% {
    transform: translate3d(50px, 40px, 0px);
    }
}

一旦你添加了这条样式的属性,刷新一下页面看看吧。你应该看到云朵欢快的上下跳动,沉浸在它自己的世界中。瓦哦。

What Just Happened

刚才你添加CSS属性是使云朵上下的跳动。CSS animation是如这么的简单啊。它能让你指定元素想要动画的起止状态,中间任意状态(即关键帧)和终止状态。我们云朵移动是非常简单的,所以学习这个动画实现是个很好的起点。

我们将着眼于第一件事就是animation属性本身:

animation: bobble 2s infinite;

animation属性的职责是设置动画的本身。 你使用它的简写形式,你将声明三件事:

    1. The name of your animation:动画(帧)的名字
    1. The duration:持续时间
    1. The number of times your animation will loop:动画迭代的次数

animation声明是不同的。我们这里将名字起为bobble,动画持续时间2秒,这里设置迭代的次数是无数次。

What About the Vendor Prefixes?

animation属性还是比较新的,所以一些浏览器需要添加私有的前缀才能使之工作。不要将各种浏览器前缀的属性全都堆上去。而是使用类似-prefix-free库 (未译),就像这个例子一样,同时能运行在你的旧的浏览器(需要私有前缀版本的浏览器)中。

正如你看到的,animation声明没有包含更多的动画细节。它设置动画的更高面东西,而一个CSS animation的详细内容,是定义在@keyframes规则里。 Let's look at our @keyframes rule to learn more:==让我们来看看我们的@keyframes规则,深入学习:

@keyframes bobble {
    0% {
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
    50% {
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }
    100% {
    transform: translate3d(50px, 40px, 0px);
    }
}

首先,看下@keyframes属性。在外层包含@keyframes声明的名字:

@keyframes bobble {/*highlight line*/
    0% {
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
    50% {
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }
    100% {
    transform: translate3d(50px, 40px, 0px);
    }
}

在内层,它包含样式规则(即实际的关键帧),使用百分比或fromto关键字:

@keyframes bobble {
    0% {/*highlight line*/
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
    50% {/*highlight line*/
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }
    100% {/*highlight line*/
    transform: translate3d(50px, 40px, 0px);
    }
}

你所期望的几乎就是这些关键帧样式规则。他们只包含CSS属性,如transformanimation-timing-function,当动画到该关键帧时,会应用该帧的属性值。我们不久会回到这个问题,因为你需要知道有一个重要的细节-----关键帧样式规则。

The Name

那么,我刚才解释的那部分,是很好理解的。这儿有些事情会变得有点混乱。 尽管,在anaimation规则中定义动画属性,又另一个样式@keyframes规则中声明你的关键帧,他们非常绑定十分紧密。如果它不是那么复杂和凌乱,这将是非常优美的。但我们的工作,就是解开这个烂摊子,弄清楚到底是怎么回事,并最终能够以更复杂的方式创建动画。

命名为bobble的关键帧@keyframes规则来标识关键帧的行为,并用作animation的属性值:

#bigcloud {
    animation: bobble 2s infinite;/*highlight line*/
    margin-left: 100px;
    margin-top: 15px;
}
@keyframes bobble {/*highlight line*/
    0% {
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }

    50% {
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }

    100% {
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
}

@keyframes 规则名字也是bobble,这并不是说animation属性指向bobble是一个巧合。如果这两个名称不一致,你的动画将无法正常工作。

Duration and the Keyframes

上一节内容你学到了animation的关键帧属性。解决了这个难题。更大的难题是,动画的持续时间,及某个特定关键帧样式实际触发的时间。

你该记得,当你在@keyframes中定义关键帧样式,你设置的不是一个真实的值。它是一个百分比或是from/to关键字:

@keyframes bobble {
    0% {/*highlight line*/
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
    50% {/*highlight line*/
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }
    100% {/*highlight line*/
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
}

在我们的例子中,关键帧选择的百分比值是0%,50%和100%。它们表示的是已完成动画的百分比。当你的动画刚刚开始时,你已经完成了动画的0%。 0%关键帧将被触发。当你的动画执行一半了,50%的关键帧得到触发。在动画的最后,100%的关键帧将被触发。

About the from / to Selector

在选择器中,你可以使用等效的关键字from,来代替0%;使用to关键字代替100%。我不知道为什么有人想到会用它,但它确实存在,在实际编码中最好将它抛开。

在此章节中,我不太愿意使用from/to关键字。使用该关键字,就被固定死了,对以后的扩展更不通用。

animation上的属性持续时间是描述整个动画的时间,除非你设置动画运行的总时间, 该值用来标识随时间进行的精确百分比(关键帧)。那么,动画就正常结束。

下图的百分比是映射2秒动画时间单位上的具体时间值:

Animation Img

这部分对我来说是复杂。一旦你理解duration是怎样映射的划分的关键帧,你将在理解动画这块儿跨越的一个重要障碍。

无论如何,我想我们已经看到一个简单动画原理的足够细节。你学会了怎样使用animation声明一个动画,和添加@keyframes规则。 我们也花了一些时间来了解它们组合 一起的产生效果。

不过,还没有做完。还有涉及更多更详细,休息一下,然后看看这个How Addicted To Facebook You Are quiz。在看到你的结果后轻轻地抽泣了几分钟,你会在一个的完美状态,以了解更多关于CSS animation!

Detailed Look at the CSS Animation Property

刚才我们看到,animation属性包含了更多的属性。现在,你涉足创建一个动画,让我们做一些令人乏味事,学习animation所有的属性。为了更好的学习它,首先扩展它的简写,看看它具体的形式。我们简写形式看起来像下面一样:

animation: bobble 2s infinite;

它的全名称是下面这样:

animation-name: bobble;
animation-duration: 2s;
animation-iteration-count: infinite;

上面简写的形式扩展为三个属性animation-nameanimation-durationanimation-iteration-count。这些属性现在深印到你的脑海中了吧,让我们继续看一下我们没有用过的属性比如:animation-play-state, animation-delay, animation-direction, animation-fill-mode, 和 animation-timing-function

Onwards!

Pausing and Resuming an Animation

默认,你的动画开始第一次时,animation属性就被激活。在我们简单的例子中,意味着页面被加载时激活。首先,我们简单想象它被设置成2秒无限循环的动画:

Animation Img

每个黄色矩形表示动画的一次迭代。如果你把动画并排的每次迭代中,你就会得到看起来像我上面所示的那样。

一旦动画开始,在它结束之前永远不会停止。如果你的动画设置为循环,终止状态完成后,它会从起止状态继续执行。它是每次迭代表示为一个单独黄色矩形的循环。我们目前bobble动画是就是这样的。

有时候,你可能 不想要上面那种行为。如果你希望你的动画暂停,不让动画初始状态属性被激活,你可以用动画animation-play-state属性。这个属性允许你在播放运行时的暂停播放的切换。

默认情况下,animation-play-state属性设置为running。你可以将该值设置为paused,停止在运行的过程中:

animation-play-state: paused;

当动画暂停时,它保留动画运行最后时刻的计算值:

Animation Img

它停在那儿几乎不动,你可以通过设置它的animation-play-state属性值为running.来恢复运行。在恢复运行之前,它不会突然从起止状态重新运行:

Animation Img

就像你预期的一样,动画从当前状态平滑的运行,就像媒体播放器的播放和暂停功能一样。

Delaying and Offsetting the Animation

如果你希望你的动画不是立即播放,而是经过一段时间后播放,你应当使用animation-delay属性。此属性允许你经过指定的时间秒数后,动画才开始运行:

animation-delay: 5s;

延迟不是等5秒之后0%关键帧被触发。它是第一次迭代的0%关键帧被触发:

Animation Img

一旦你的动画开始运行时,延迟值就没有用武之地了。以后每一次迭代的动画(如果有的话)一个接一个无间隔的运行。

现在你可以给这个属性赋其他的值,你可以给animation-delay设置负值。

animation-delay: -.25s;

当你设置了一个负值,你的动画会在超前执行你设置的那个值。设置animation-delay-.25秒就是这样:

Animation Img

负值作为一个标识,告诉浏览器这是一个偏移而不是延时。是的,这有点奇怪,因为它给的属性名是animation-delay,我只是个传教者。还有更奇怪的呢,一旦你设置这个负值大于每一次动画迭代的时延,这是没问题的。只要保证有足够的迭代数,无论落在哪次迭代点动画就开始。如果你没有足够的迭代数来抵消那个负值,你的动画根本无法运行。

Hold My Keyframe Properties, Please!

如果你不设置动画循环,你会发现,一旦动画结束后,关键帧设置任何属性将被清除,元素返回到一个动画起止状态。这是因为关键帧应用于的属性是瞬时的。当关键帧是激活状态时,它们才存在,在以外任何时间,这些属性值都不能存在。如果你不想要这种行为,当它运行完毕,你的动画看起来像突然跳到开始位置或突然复位,让我们来看看这两种情况的区别,然后看看如何更改默认行为。

Waiting to Start

第一个用例是当你设置了animation-delay属性。例如,设置了5s:

Animation Img

动画需等待5秒才开始执行,此时关键帧没有被执行。在等待时间中,第一个关键帧的所有属性都不会生效。

Animation is Done

第二个例子,当你的动画完成后。该例子是你设置循环3次的那个示例:

Animation Img

3次迭代完成后,最后关键帧的所有属性都会消失。动画回到原始状态就像什么也没有发生过一样。

Meet animation-fill-mode

如果你想在等待延时过程中,想让第一侦生效,或当动画完成后,保留最后一侦,你可以设置animation-fill-mode属性。属性值如下:

    1. none There is no faking the property values here. If you want the a keyframe's property values to apply, your keyframe must be active.默认值,不设置动画之外的状态
    1. forwards After your animation has run to completion, any property values the animation had at the end will be maintained.当你的动画完成后,保持动画结束时的状态
    1. backwards The animation will apply the property values from the starting keyframe even if that keyframe is not active yet.动画将保持开始关键帧的属性值,虽然它未处于激活状态
    1. both This is the ultimate solution. Your animation will apply the property values of the first keyframe at the beginning and maintain the property values of the last keyframe at the end.最后的一个值。你的动画在停在起止状态时,第一帧被应用,终止状态最后一帧被激活。

刚才我创建的是无限迭代和开始时没有延时的动画。我创建的许多动画的属性在开始帧、结束帧、无动画状态的动画元素之间没有太多的不同。正因为如此,我从不会熬夜担忧,也不会因为不想用animation-fill-mode的属性而感到担忧。

译者注:实例参见携程UED的demo

Reversing an Animation (or Alternating Directions)

现在,让我们看一下这个略微奇幻的属性,动画默认从0%到100%循序播放。你可以通过给animation-direction设置normal, reverse, alternate, alternate-reverse来 改变这个行为, normalreverse能够直接指出他们做什么,让我们来看一些比较有意思的属性值:alternatealternate-reverse.

当设置animation-direction 属性值为alternate-reverse,动画正常开始。在第二次迭代时,它反向运行,以后会正向,反向交替着运行:

Animation Img

设置animation-direction属性值为 alternate 与上面十分相似,但有点细微的不同:

Animation Img

动画开始于反向运行,然后正向,反向交替 运行。

At Easing, Soldier!

涉及到的最后一个有关联的动画属性是animation-timing-function. 它的功能是在开始和结束之间指定如何改变属性值。在 [Easing Functions in CSS3][](未译) 的教程中有更多缓动函数的细节, 所以去那边详细学习吧。

The Animation Shorthand

我们看下已经学过的animation属性的简写方式:

#somethingSomethingDarkSide {
    animation-name: deathstar;
    animation-duration: 25s;
    animation-iteration-count: 1;
    animation-play-state: paused;
    animation-delay: 0s;
    animation-direction: normal;
    animation-fill-mode: both;
    animation-timing-function: ease-out;
}

有些人可能更喜欢使用所有的属性简写到animation属性中。事实上,正如你看到的,bobble动画就是使用的简写:

animation: bobble 2s infinite;

你上面看到的所有的全称属性都可表示为简单写的形式---只是好记而已。如果你对此疑惑,下面是他们的映射顺序:

animation: <animation-name> <animation-duration> <animation-timing-function> <animation-delay> <animation-iteration-count> <animation-direction> <animation-fill-mode>;

尖括号中的部分来代替全称属性名。注意,简写属性中没法表示animation-play-state。你必须使用全称属性名及值也表示它。

无论怎么写,将一般写法写成简写形式,都会像下面一样:

#somethingSomethingDarkSide {
    animation: deathstar 25s ease-out 0s 1 normal both;
    animation-play-state: paused;
}

简写的形式比全称写法紧凑吧?对的!它更容易理解吗?这是一个很难回答的一个问题,完全基于你(或你的团队)的偏好。

我一般比较喜欢使用animation-name, animation-durationanimation-timing-function 的简写版本,是因为很容易记住它。一旦超过这三个属性后,我就不得不去查阅文档添加哪一个了。

你们的分歧可能是在全称与简单属性上,所以不管卡怎样选择一个适合你的。呃...以你的聪明头脑,是时候告别animation 属性的内容了,来关注动画世界中其它的美妙的旅程吧。

Looking at the Keyframes

迄今为止,大部分时间花在动画animation和它怎样影响你的整体部分…动画。一个CSS动画真正的角色是关键帧,所以让我们更多的关注在这一节。

再次看一下bobble关键帧们:

@keyframes bobble {
    0% {
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
    50% {
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }
    100% {
    transform: translate3d(50px, 40px, 0px);
    }
}

早先提到的一个关键帧十分像一个属性样式。把CSS属性放进去,当这些关键帧被触发时,这些属性被执行。注意的是,并不是所有的属性都可应用于关键帧中,只有可动画的CSS 属性animation-timing-function才能被指定。

这不一定是个坏消息,我完全确定你所有放到关键帧中属性列表中的属性都是可进行动画化的。你访问这里就能看到所的可动画的属性完整列表,以及[这里][8]是一些额外的属性。

最后,看一下可以指定到关键帧中的 animation-timing-function 属性,这个属性影响着从当前帧怎样过滤到下一关键帧。拿我们例子说,在0%关键帧,我们设置animation-timing-function 属性值为ease-in:

@keyframes bobble {
    0% {
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
    50% {
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }
    100% {
    transform: translate3d(50px, 40px, 0px);
    }
}

当你的动画从0%关键帧到50%关键帧滚动时缓动函数被激活。同样的,动画从50%关键帧到100%关键帧滚动时50%处的关键帧被激活。从当前帧到下一帧过程中给定的缓动函数被激活,在100%关键帧声明一个调速函数没有太多意义。

Reusing Keyframes

最后要讲的,是另一个动画声明复用同一个关键帧定义。我有点担忧过早将animation属性和@keyframes规则分离开,这样做起来有点小笨重。即使再笨重的东西,如果你付出更多努力,这儿会有一些漂亮的事情做。

一个是声明另一个animation属性时可以使用同一个关键帧定义。也许很难明白我的意思,让我们扩展当前的例子来强调我在说什么。

在当前的HTML文档中包括一个弹跳云朵,继续添加下面的高亮行:

<!DOCTYPE html>
<html lang="en-us">

<head>
<meta charset="utf-8">
<title>Bouncing Clouds</title>
<script src="http://www.kirupa.com/js/prefixfree.min.js"></script>

<style>
#mainContent {
    background-color: #A2BFCE;
    border-radius: 4px;
    padding: 10px;
    width: 600px;
    height: 300px;
    overflow: hidden;
}
.cloud {
    position: absolute;
}
#bigcloud {
    animation: bobble 2s infinite;
    margin-left: 100px;
    margin-top: 15px;
}
#smallcloud {
    animation: bobble 4s infinite;
    margin-top: 65px;
    margin-left: 200px;
}
@keyframes bobble {
    0% {
    transform: translate3d(50px, 40px, 0px);
    animation-timing-function: ease-in;
    }
    50% {
    transform: translate3d(50px, 50px, 0px);
    animation-timing-function: ease-out;
    }
    100% {
    transform: translate3d(50px, 40px, 0px);
    }
}
</style>
</head>

<body>
    <div id="mainContent">
    <img id="bigcloud" alt="#" class="cloud" height="154" src="http://www.kirupa.com/images/bigCloud.png" width="238">
    <img id="smallcloud" alt="#" class="cloud" height="103" src="http://www.kirupa.com/images/smallCloud.png" width="158">
    </div>
</body>

</html>

一旦你添加高亮#smallCloud样式和第二个img元素后,重新预览一下页面。如果没其它错误的话,你将看到两块云朵愉快的跳动...就是本文最开始的那个例子一样。

现在你的例子能运行了,看一下是如何做到的。窍门就是#smallCloud样式的中animation声明行。 #smallcloud { animation: bobble 4s infinite; margin-top: 65px; margin-left: 200px; }

注意这里引用同一个@keyframes规则名称为bobble。和#bigClound样式唯一不同的是animation声明中的时延。小的云朵中animation时延设置成4秒---比大的云朵设置时延长两倍:

#bigcloud {
    animation: bobble 2s infinite;
    margin-left: 100px;
    margin-top: 15px;
}

两个云朵中定义的bobble关键帧有什么意思呢。唯一不同是一个动画在2秒中执行完那些关键帧,另一个是4秒:

Animation Img

animationkeyframes声明分离开来,可以做这上面的事。animation中的任何属性的改变都会影响到关键帧这一水平--就像这儿你看到的时延。刚才我解释的每个animation属性的设置,不用直接涉及关键帧部分,就会改变关键帧的行为。

You have to admit, that is pretty cool.

Declaring Multiple Animations

最后要讲的(好吧,真的最后一次),快速看一下怎样在同一个animation 属性中声明多个动画。简写形式,用逗号隔开每个动画定义,如下:

#oppaGangnamStyle {
    animation: hey 2s infinite, sexy 1s infinite, lady 5s infinite;
}

注意上面每一个动画定义指向不同的@keyframes。不管怎样,如果在同一个animation属性声明中指向同一个@keyframes关键帧,根据CSS优先顺序,最后一个将被生效。

属性名全称形式,看起来如下:

#oppaGangnamStyle {
    animation-name: hey, sexy, lady;
    animation-duration: 2s, 1s, 5s;
    animation-iteration-count: infinite;
}

这次,应该是比较简单的。都是使用逗号隔开的,如果在为一个属性使用多个值有疑惑时,仅仅使用逗号就可解决。

Conclusion

我们已经了解到CSS中animation属性很多的内容---特别是想让你的内容更加活泼。你已经学习了动画的基本内容,继续学习下面教程吧:


翻译水平有限,敬请各位同学批评指正。


Comments

comments powered by Disqus