时间:2021-07-01 10:21:17 帮助过:40人阅读
首先,我们来看看一个例子。下面是一个CSS动画,应用于云朵上,使得它们可以轻轻地上下弹跳:
本教程中,你将学习关于CSS动画内容,而不仅是创建一些类似移动云朵的东西,还包括一些更酷且实用的东西。你将学习如何实用 animation 属性定义一个CSS动画,如何使用 keyframes ,以及如何调整各种动画相关的属性,来完成你想要的动画效果。
开始!
学习CSS动画最简单(也最有趣)的方式是实践,然后再学习原理。先创建一个新的HTML文件,然后添加如下的HTML和CSS。
Bouncing Clouds
预览一下,你会看到如下的内容。一朵偏离中心立着的云:
接下来我们来添加动画。添加CSS动画一共需要两步。首先,设置 animation 属性。然后定义 keyframes 并指定添加那些动画效果。
从上面的标签中,找到 #bigCloud 样式规则,添加如下的 animation 属性:
#bigcloud { animation: bobble 2s infinite; margin-left: 100px; margin-top: 15px;}
animation 这一行属性的意义我们暂时不需要理解,后面我们会讲到。然后,我们添加keyframes。 @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); }}
添加了以上的样式规则后,再次预览页面。你可以看到白云已经愉快地跳动起来了。
我们先添加了一个CSS动画,使得白云跳动起来。现在,CSS动画到底是什么,也很简单。它允许你指定元素的某些特定属性(用于完成动画效果)的开始状态,任何中间状态(即关键帧),以及结束状态。上面例子中的云朵的移动非常简单,所以将它作为我们学习的入门,非常合适。
首先,我们看看 animation 属性:
animation: bobble 2s infinite;
animation 属性用于设置动画。我们常用的是如上的简写,需要指定三个值:
我们的 animation 声明正确。动画名称为 bobble ,时长 2s ,并设置 infinite 无限循环。
animation 属性目前还是非常新的(2013年),所以很多浏览器需要添加前缀才可以使用。不要把标签弄混了。另外,使用一些如 -prefix-free library 这样的工具可以保持标签简洁,同时也允许旧版的浏览器可以查看动画。
如你所见, animation 声明并没有包含动画方面太多的细节内容。它设置的是比较高层面的定义,关于你的动画将会做什么,但是实质的CSS动画的声明,主要是放在 @keyframes 规则中。
接下来看看 @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 :
然后,包含样式规则(即实际的关键帧),选择器是百分比 0% 50% 100% ,也可以是关键字 from 和 to :
@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); }}
这些关键帧规则非常规范。它们包含了如 transform 和 animation-timing-function 的CSS属性,当 @keyframes 规则起作用时,这些属性的值也会被应用在元素上。有一个关于关键帧样式规则的内容我们需要注意一下。
我刚才解释的部分其实是很容易理解的,但是有块内容需要注意一下。尽管 animation 属性是在另一个样式规则中声明的,而关键帧则是在自己的 @keyframes 规则中声明的,它们是相互绑定的,缺少任何一个都不可以。
我们先看看 animation 属性和 @keyframes 规则是如何绑在一起的。
给 @keyframes 规则的名称充当了标识符的角色, animation 属性用它来找到对应的keyframes:
#bigcloud { animation: bobble 2s infinite; margin-left: 100px; margin-top: 15px;}@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); animation-timing-function: ease-in; }}
我们的 animation 属性引用 bobble 并不是一个巧合,因为我们的 @keyframes 规则名称也是 bobble 。如果这两个名称不一致,动画就无法工作。
从前面的部分,可以看到我们的 animation 属性和它的关键帧如何对应上。解决一个问题之后,我们来看看下一个。动画的时长和一个特定的关键帧规则实际作用的关系。
你还记得,当你在 @keyframes 规则中,定义关键帧样式规则,你的选择器并不是一个具体的时间值。而是一个百分比值或者 from 和 to 关键字:
@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); animation-timing-function: ease-in; }}
在我们的例子中,关键帧选择器是百分比, 0% , 50% , 100% 。它们表示动画已经完成了多少。动画刚开始时,你的动画完成了 0% 。此时 0% 关键帧起作用。当你的动画进行到一半, 50% 关键帧起作用。当动画结束时, 100% 关键帧起作用。
如果不使用 0% 作为选择器,你可以使用 from ,两者等同。二 100% 则对应 to 关键字。我不太清楚为什么会有人用 from 和 to ,但是了解一下还是必要的。
我不是不支持 from 和 to 。只是它们的存在对我写CSS动画并没有什么影响。
animation 属性中的 duration 值,除了设置动画运行的总时长,还帮助你根据实际的时间单位编写合适的百分比值。
下图是百分比值到 2s 的动画的时间单位的映射:
这对我来说也有点困惑。理解了 duration 是如何映射到单独的关键帧上之后,你就跳过了主要障碍——在脑海中想象动画如何进行。
接下来,我们来深入看看一个简单的CSS动画是如何工作的。你已经知道了如何使用 animation 属性声明一个动画,以及 @keyframes 规则中的关键帧样式是如何写的。我们也花了一点时间来学习动画是如何运行的。
还没完成,还有很多更详细的内容。
animation 属性其实比我们刚刚看到的要更完整。 先尝试创建一个动画,然后了解 animation 属性。为了帮助学习,我们首先把下面这行简写换成完整的写法。简写版如下:
animation: bobble 2s infinite;
完整写法如下:
animation-name: bobble;animation-duration: 2s;animation-iteration-count: infinite;
简写版中的三个属性分别是 animation-name 、 animation-duration 、 animation-iteration-count 。这些属性你应该已经非常熟悉了,所以我们来看看另外的我们还不熟悉的属性,如: animation-play-state 、 animation-delay 、 animation-direction 、 animation-fill-mode 、 animation-timing-function 。
开始!
默认情况下,你的动画开始时,你的 animation 属性中的样式规则也就起作用了。简单来讲,也就是页面加载的时候。首先,我们简单想象一个 2s 的动画,并设置了无限循环:
每个黄色的矩形表示你的动画的一次迭代,也就是一个矩形表示执行了一次动画。如果你把每个矩形并排放置,结果如上图。
一旦动画开始,它不会停下,直到动画结束。如果你的动画设置了循环,它就会在每一次结束的时候又立刻重新开始。每一次循环用一个单独的黄色矩形表示。我们目前的 bobble 动画就是这样。
有时候,你可能不想要这样。如果你希望动画不要在样式规则激活时立刻执行,或者你想要在中间某个时刻暂停动画,你可以尝试 animation-play-state 属性。这个属性允许你切换动画的状态为 running 或 paused ,无论动画是否正在进行。
默认情况下, animation-play-state 属性的值为 running 。你可以设置为 paused 来暂定动画。
animation-play-state: paused;
当动画暂停时,它会保留动画的所有最后的计算值:
就好像时间突然静止了。你可以通过设置 animation-play-state 属性来恢复 running 。恢复之前,动画不会回到0%的位置突然重新开始:
你的动画将平滑地从你暂停的位置继续,和媒体播放器的播放和暂停键一样。
如果你想让你的动画在某一段时间内不要播放,你可以看看 animation-delay 属性。这个属性可以让你指定动画播放的延迟时间。
animation-delay: 5s;
延迟不是发生在 0% 关键帧开始后,等待 5s 。而是在 0% 关键帧之前,在动画第一次迭代之前:
一旦动画开始运行,延迟的值将不会再起作用。动画的每一次后续的迭代(如果还有),都是一个结束另一个马上开始,没有延迟。
现在,这里有一些关于这个属性的内容。 animation-delay 的值除了可以是正数,也可以是负数:
animation-delay: -.25s;
当你指定了一个负值,你的动画就会马上开始,但是会相对你指定的 duration 有一定的偏移。如果 animation-delay 的值为 -.25s ,结果如下:
负值代表一个信号,告诉浏览器将这个值作为偏移量,而不是延迟。是的,这有一点奇怪,特别是这个属性明明叫 animation-delay 。比较不奇怪的是——如果你指定的偏移量比动画一次迭代的时长还要大的话,那这就不是问题了。你的动画将会从起点落在的迭代中开始(比如起点出现在第二次迭代的时间段中)。只要确保你的动画有足够多次的迭代,可以包容起点。如果你没有足够的迭代,你又指定了一个比较大的偏移量值,你的动画就无法运行。
如果你没有让动画循环,你会注意到一旦动画结束,关键帧设置的属性都会移除,你的元素就回到动画播放前的状态。这是因为你通过关键帧应用的属性都是暂时性的。当关键帧起作用时,这些属性值就是存在的,一旦离开了那个窗口,这些属性值都不会保留。如果你不希望这种行为,你的动画可能会在结束的时候突然跳到初始位置或者突然重置。我们先来看看两个例子,然后看看如何改变这种默认行为。
第一种情况发生在,当你处理一个 animation-delay 时。例如,你指定了 5s 的延迟:
你的动画会等待 5s ,你的关键帧都不处于激活状态。第一个关键帧包含的所有属性,在这 5s 的延迟中都不会被激活。
第二种情况是你的动画已经完成后,尝试指定动画循环三次:
最后,在第三次迭代的最后一帧,所有指定的属性都会消失。应用了动画的元素会回到动画没开始前的状态。
如果你希望开始的关键帧的属性在 delay 期间就激活,或者最后的关键帧的属性在动画结束之后仍然保持,你可以通过设置 animation-fill-mode 属性来完成。如下:
我创建的动画是永远循环的,开始的时候没有延迟。我创建的很多动画的起始关键帧、结束关键帧、元素的非动画状态的属性值之间都没有很大的差异。因为这样,我从来不纠结上面的问题,所以在 animation-fill-mode 属性声明这里不要感到压力。
现在,我们来看看另一个属性。默认情况下,动画从 0% 按照顺序播放到 100% 。你可以通过设置 animation-direction 属性来改变这种行为,无论是正常 normal 、反转 reverse 、交替 alternate 或者反转交替 alternate-reverse 。 normal 和 reverse 都相对简单,所以我们来看看另外两个比较有趣的值: alternate 和 alternate-reverse 。
当你将 animation-direction 的值设置为 alternate ,你的动画开始时正常的。第二次迭代的时候,它就变成反方向的,然后接下来都在正序和反序中交替:
将 animation-direction 设置为 alternate-reverse ,它和上一个值相似但是有一点不同:
动画开始是反向的,然后在正序和反序之间交替。
注:原文为 alternate 先反向后正向, alternate-reverse 先正向后反向,有误,已改正。
最后一个动画相关的属性是 animation-timing-function 。这个函数允许你指定开始和结束之间的动画时间函数。我在 Easing Functions in CSS3 一文中介绍了一些功能函数,欢迎了解。
我们目前看到的属性都是完整的写法:
#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-play-state 属性不能简写,你需要另外单独写。
无论如何,把完整写法变为简写,结果如下:
#somethingSomethingDarkSide { animation: deathstar 25s ease-out 0s 1 normal both; animation-play-state: paused;}
简写版确实比完整版要方便很多,但是还是看个人(或团队)偏好吧。
我个人比较喜欢简写版来指定 animation-name 、 animation-duration 、 animation-timing-function ,因为比较好记。一旦超过了三个属性值,我就需要查阅文档了 (:зゝ∠) 。
你的情况可能要根据你个人的情况咯,所以选择适合自己的。还有,我们接下来应该看看 keyframes 部分了。
我们大部分的时间都花在了 animation 属性以及它对动画的影响上。实际上CSS动画最大的功臣是 keyframes ,所以接下来看看 keyframes 吧。
再次看看 bobble 的 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); }}
我前面提到的,一个单独的关键帧差不多相当于一个样式规则。你把CSS属性放进去,这些属性在关键帧执行到的时候就被激活。需要注意的是,不是每一个CSS属性都可以放在 keyframe 里面。只有那些可以用来做动画的CSS属性以及 animation-timing-function 才可以。
可以在 keyframe 中使用的属性,这里有一个 列表 可以查看。还有一些额外的,点击 这里 。
最后要看的是 animation-timing-function 属性,你可以在 keyframe 中指定它。这个属性的作用是,从你当前所在的关键帧到下一个关键帧之间的时间函数。在我们的例子中,在 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% 关键帧中声明的 animation-timing-function 也会在 50%~100% 之间激活。也就是这个时间函数是在当前关键帧到下一个关键帧之间工作的,所以在 100% 关键帧处声明时间函数是没有必要的。
我要讲得最后一个东西是使用相同的关键帧来用于另一个动画的声明。我前面提到 animation 属性声明,和实际的 @keyframes 规则是分开的,这对于动画其实是有点笨重的。但是如果你尝试了,还是有好的东西的。
就是你可以在另一个 animation 属性声明中重用相同的关键帧。我们下面来扩展上面的例子来看看。
在原来的HTML文档中,只包含了一朵云,而且是弹跳的,我们现在再加一朵。
Bouncing Clouds
添加 #smallCloud 样式规则,以及第二个 img 元素,然后预览页面。如果没出什么错的话,你会看到两朵云在愉快地弹跳...也就是这篇文章开头的实例。
现在你的实例可以工作了,我们来看看如何做到的。就是 #smallCloud 样式中的 animation 声明:
#smallcloud { animation: bobble 4s infinite; margin-top: 65px; margin-left: 200px;}
注意我们引用的是相同的 @keyframes 规则,名称是 bobble 。两个动画声明唯一的不同就是 #bigCloud 的时长是2秒,而另一个是4秒:
#bigcloud { animation: bobble 2s infinite; margin-left: 100px; margin-top: 15px;}
这意味着你在 bobble keyframes 中定义的属性,被应用在了两朵云上。唯一的不同是一个时长为 2s ,一个为 4s :
keyframes 和 animation 声明之间相互独立的特性允许你这样做。任何你在 animation 属性中的声明都会在另一个层面影响你的 keyframes 的运行,比如前面看到的 duration 。每个动画属性我前面都做了简单的介绍,可以影响你的 keyframes 的行为,而不需要直接接触关键帧。
这点你必须承认,很方便。
最后一件我们要看的事情是,如何在同一个 animation 属性在中声明多个动画。在简写版的声明中,直接用逗号分隔每个动画即可。
#oppaGangnamStyle { animation: hey 2s infinite, sexy 1s infinite, lady 5s infinite;}
注意每个动画都指向不同的 @keyframes 规则。如果由于某些原因,你要在同一个 animation 属性中指定相同的 @keyframes 规则,基于CSS的优先顺序,后面的动画会先执行。
译注:同一个元素应用多个 keyframes 动画,是同时执行的;如果前后应用了相同的 keyframes ,那么放在后面的先执行,再执行前面的。
如果是完整版地声明动画,如下:
#oppaGangnamStyle { animation-name: hey, sexy, lady; animation-duration: 2s, 1s, 5s; animation-iteration-count: infinite;}
同样是非常简单的。在CSS中都使用逗号分隔,所以当要为一个属性声明多个值的时候,就加个逗号吧,这个方法是值得尝试的。
CSS中的 animation 属性是一个非常重要的属性,无论是简单了解还是深入学习——特别是如果你想让你的界面内容更lively。学习了如何使用CSS动画方面的基础之后,可以再看看下面的文章:
关于CSS动画更详细的讲解可以点击here查看O(∩_∩)O
本文根据 @kirupa 的《 All About CSS Animations 》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处: https://www.kirupa.com/html5/all_about_css_animations.htm 。
在校学生,本科计算机专业。逗比一枚,热爱前端热爱生活,喜欢CSS喜欢JavaScript喜欢SVG,爱玩PS玩AI玩啊逗比的软件。努力向上,厚积薄发。