CSS 动画 第一部分:创建动画、分配动画、播放次数、方向、延迟
目录
Hello, animation!
理论
欢迎来到我们的 CSS 动画课程,这将是一次奇妙的探索!我们将走文明进化之路,征服深空。我们将在基础课程中对物体进行移动、旋转、变换。如果需要看更多的理论,请查阅 MDN 的文档;如果需要实践,我们就来看第一个任务吧!🚀
CSS 赋予你创建复杂动画的能力,你可以使用多种方式控制它们。一个 CSS 动画的描述分为两部分:一组关键帧 @keyframes
和动画参数。
下面是一个动画中简单的关键帧描述:
@keyframes stretching {
0% {
width: 100px;
}
100% {
width: 200px;
}
}
这个例子中的动画被称作 stretching
,描述了一个元素从初始状态变化到最终状态。这个动画可以被应用到任何元素上。使用动画时,你只需要添加两个属性到你的 CSS 中:动画名字和动画持续时间,并且给出相应的属性值。举个例子:
.button {
animation-name: stretching;
animation-duration: 1s;
}
这段代码会将名为 stretching
的动画应用到所有拥有 button
类的元素上。这段代码的结果是,对应的元素的宽度会在 1 秒内从 100px 逐渐拉伸到 200px。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello, animation!</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch1.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="ancient">
<div class="stone">
<div class="wood-wheel"></div>
</div>
</body>
</html>
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.wood-wheel {
animation-name: rotate;
animation-duration: 2s;
}
目标
- 动画
@keyframes rotate
的关键帧描述; .wood-wheel
类的动画规则。
示例
@keyframes
: 故事板
理论
对于每个动画,你需要定义它的名字,并使用 from
和 to
关键字或是 0%
和 100%
的值来描述其初始状态和最终状态。
同样的,你还可以使用百分数来定义更多的中间关键帧。
如果初始帧没有定义,动画会从元素的初始状态开始播放,播放到 @keyframes
描述的最近的状态,以此类推。
如果最终帧没有定义,当到达最后一个中间状态后,动画将继续播放到元素的初始状态。
@keyframes
中的帧可以按任意顺序排列,但推荐按升序排列。
动画的持续时间,即 animation-duration
属性,接收毫秒或秒值,例如:10s
、100ms
。
下面我们来试一下创建一个动画,不提供初始值,只提供 50%
和 100%
两个关键帧。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>@keyframes: storyboard</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch1.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="ancient">
<div class="stone">
<div class="barrow-wheel"></div>
</div>
</body>
</html>
.barrow-wheel {
animation-name: rotate;
animation-duration: 2s;
}
@keyframes rotate {
50% {
transform: rotate(-90deg);
}
100% {
transform: rotate(360deg);
}
}
目标
为 50% 关键帧添加角度旋转
rotate(90deg)
,为 100% 关键帧添加旋转360°
。将 50% 关键帧的旋转角度调整为
-90°
。
示例
@keyframes: from
和 to
理论
像上节课所讲解的那样,初始和最终的关键帧是由 from
和 to
或 0%
和 100%
的值来定义的。
中间状态的关键帧是由百分数形式的值来定义的,下面是一个包含四个帧的动画:
@keyframes coloring {
from { background-color: red; }
33% { background-color: yellow; }
66% { background-color: green; }
to { background-color: blue; }
}
接下来我们来尝试一下 from
to
和中间状态的关键帧!
目标
创建一个名为 list-up
的动画,包含如下关键帧:
from
初始帧是transform: translateY(0px)
;50%
帧是transform: translateY(-250px)
;100%
最终帧是transform: translateY(-300px)
。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>@keyframes: from and to</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch1.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="ancient">
<div class="lift-top">
<div class="platform">
<span class="stone-wheel"></span>
</div>
</div>
</body>
</html>
.platform {
animation-name: lift-up;
animation-duration: 3s;
}
@keyframes lift-up {
from {
transform: translateY(0px);
}
50% {
transform: translateY(-250px);
}
100% {
transform: translateY(-300px);
}
}
示例
@keyframes: 帧分组
理论
@keyframes
中的关键帧可以成组,把关键字放到逗号分隔的字符串中即可。我们看下面的例子:
@keyframes stretching {
0%, 50% {
width: 100px;
}
100% {
width: 200px;
}
}
在这个例子中,前两个帧组成了一个组。对应的元素会在动画开始后宽度变为 100px
,并且整个动画的前一半时间内都保持 100px
的宽度。然后,该元素的宽度会从 100px
变为 200px
。
目标
- 将
50%
的帧改为50%, 80%
; - 将
50%, 80%
中的动画改为transform: translateY(-50px)
。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>@keyframes: frame grouping</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch1.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="ancient">
<div class="lift-top">
<div class="platform">
<span class="stone-wheel"></span>
</div>
</div>
</body>
</html>
.platform {
animation-name: lift-up;
animation-duration: 3s;
}
@keyframes lift-up {
0% {
transform: translateY(0px);
}
50%, 80% {
transform: translateY(-50px);
}
100% {
transform: translateY(-300px);
}
}
示例
复杂动画,其一
理论
更多时候,我们会将很多动画分配给同一个元素。
如果这些动画中变换了元素不同的属性,这些动画效果会同时播放。
在这一节和下一节中,我们会尝试在同一个项目中创建一个复杂的动画。首先我们创建第一个动画,并分配给页面元素。
目标
创建一个叫做
rotate
的动画,在关键帧50%
的时候做一个旋转变换transform: rotate(360deg)
。将这个动画分配给
.stone-wheel
,并设置持续时间3s
。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Complex animation, step 1</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch1.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="ancient">
<div class="lift-bottom">
<span class="stone-wheel"></span>
</div>
</body>
</html>
@keyframes rotate {
50% {
transform: rotate(360deg);
}
}
.stone-wheel {
animation-name: rotate;
animation-duration: 3s;
}
示例
复杂动画,其二
理论
接下来我们看一下如何能为元素分配第二个同时播放的动画。
假设我们有如下两个动画:
@keyframes move {
to { left: 100px; }
}
@keyframes stretch {
to { width: 100px; }
}
要给一个元素分配第二个动画,你需要添加它们的动画名称和持续时间,使用逗号分开。
.element {
animation-name: move, stretch;
animation-duration: 5s, 5s;
}
在这个例子中,两个动画将同时开始,元素将会在 5 秒内同时移动和拉伸。
多重动画就像背景和阴影的 css 属性那样,传入多个值,用逗号分隔即可。
我们继续上一节的代码,为元素添加另一个动画吧。
目标
创建一个叫做
move
的动画,包含如下关键帧:50%
:bottom: 0px
;100%
:bottom: -50px
。
添加第二个移动的动画,持续时间
6s
,分配给.stone-wheel
元素。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Complex animation, step 2</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch1.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="ancient">
<div class="lift-bottom">
<span class="stone-wheel"></span>
</div>
</body>
</html>
@keyframes rotate {
50% {
transform: rotate(360deg);
}
}
@keyframes move {
50% {
bottom: 0px;
}
100% {
bottom: -50px;
}
}
.stone-wheel {
animation-name: rotate, move;
animation-duration: 3s, 6s;
}
示例
水上冒险
理论
在我们学习 CSS 的过程中,我们将目睹文明的演变。现在我们将前往一个充满机械装置和齿轮的新世界。
你的任务就是创建必要的动画然后驾驶轮船驶向海外。animation-name
和 animation-duration
已经定义好了。
目的
创建一个动画
move-clouds
,包含一个关键帧to
,进行变换translateX(-1000px)
,创建一个动画
move-sun
,包含关键帧to
,进行变换translate(350px, -400px)
,创建一个动画
move-ship
,包含关键帧to
,进行变换translateX(1000px)
。让彗星也动起来。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Water adventure</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch1.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="ancient-world">
<div>
<div class="comet"></div>
<div class="sun-small"></div>
<div class="clouds"></div>
<div class="water"></div>
<div class="ship"></div>
</div>
</body>
</html>
@keyframes move-clouds {
to {
transform: translateX(-1000px);
}
}
@keyframes move-sun {
to {
transform: translate(350px, -400px);
}
}
@keyframes move-ship {
to {
transform: translateX(1000px);
}
}
.ship {
animation-name: move-ship;
animation-duration: 40s;
}
.clouds {
animation-name: move-clouds;
animation-duration: 40s;
}
.sun-small {
animation-name: move-sun;
animation-duration: 10s;
}
.comet {
animation-name: move-comet;
animation-duration: 10s;
}
@keyframes move-comet {
100% {
transform: translate(500px, 400px);
}
}
示例
动画播放次数
理论
在我们之前的例子中,我们都是创建了一个只能播放一次的动画,然后元素就会恢复到它们的原始状态。我们可以通过 animation-iteration-count
属性,指定动画播放的次数。
该属性接收正整数或 0。如果是 0,该动画不会播放;其它情况下,动画会按照传入的数字播放对应的次数。
该属性还可以传入 infinite
,此时该动画将会一直播放永不停止。
我们来试一下。
目标
为箭头
.arrow
分配一个持续2s
的rotate
动画。然后将播放次数设置为
2
。然后让播放次数变为无限。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Animation play count: animation-iteration-count</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch2.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="mechanical">
<div class="clock">
<span class="arrow"></span>
</div>
</body>
</html>
@keyframes rotate {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(90deg);
}
100% {
transform: rotate(0deg);
}
}
.arrow {
animation-name: rotate;
animation-duration: 2s;
/* animation-iteration-count: 2; */
animation-iteration-count: infinite;
}
示例
动画方向,其一
理论
除了动画的播放次数之外,我们还可以使用 animation-direction
来定义元素旋转的方向。默认情况下,动画是正常 normal
方向。
然而,你可以逆转动画方向,让动画倒着播放。换言之,动画将会从 to
开始播放,播放到 from
。如果要这样做,为 animation-direction
属性设置 reverse
。
我们在下面的例子中对比两种动画方向。
目的
为大齿轮
gear-big
设置动画clockwise
,持续时间2s
。然后为小齿轮
.gear-small
设置动画counterclockwise
,持续时间2s
。然后将两个齿轮的动画方向反转。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Animation direction: animation-direction, step 1</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch2.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="mechanical">
<div class="mechanism">
<span class="gear-big"></span>
<span class="gear-small"></span>
</div>
</body>
</html>
@keyframes clockwise {
to {
transform: rotate(180deg);
}
}
@keyframes counterclockwise {
to {
transform: rotate(-180deg);
}
}
.gear-big {
animation-name: clockwise;
animation-duration: 2s;
}
.gear-small {
animation-name: counterclockwise;
animation-duration: 2s;
}
.gear-big, .gear-small {
animation-direction: reverse;
}
示例
动画方向,其二
理论
animation-direction
还有另外两个值,可以在动画播放次数 animation-iteration-count
大于 1 的时候可以使用。它们定义了动画在播放时的交替方向。
如果设置为 alternate
,奇数次播放正常,偶数次播放反转。
.element {
animation-name: move;
animation-duration: 1s;
animation-iteration-count: 2;
animation-direction: alternate;
}
在上面的例子中,move
动画将播放两次:第一次(奇数次)向前,第二次(偶数次)反过来。
如果设置为 alternate-reverse
,奇数次将被反转,偶数次正常播放。
我们在下面的例子中看看这个属性是如何生效的。
目标
将两个齿轮的播放次数都设置为
2
,设置交替方向播放,
设置反向交替方向播放。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Animation direction: animation-direction, step 2</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch2.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="mechanical">
<div class="mechanism">
<span class="gear-big"></span>
<span class="gear-small"></span>
</div>
</body>
</html>
@keyframes clockwise {
to {
transform: rotate(180deg);
}
}
@keyframes counterclockwise {
to {
transform: rotate(-180deg);
}
}
.gear-big {
animation-name: clockwise;
animation-duration: 2s;
}
.gear-small {
animation-name: counterclockwise;
animation-duration: 2s;
}
.gear-big, .gear-small {
animation-iteration-count: 2;
animation-direction: alternate;
/* animation-direction: alternate; */
}
示例
动画延迟,其一
理论
除了控制动画的持续时间之外,我们还可以设置在动画开始播放之前的延迟。
在这节和接下来的两节中,我们将创建两个动画,然后使用延迟功能,让它们依次运行。首先我们创建第一个动画,并分配给相应的元素。
目标
创建一个
rotate
动画,包含一个to
关键帧,动画内容是旋转360deg
,然后将这个动画分配给
.arrow-small
,持续时间1s
。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Animation delay: animation-delay, step 1</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch2.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="mechanical">
<div class="alarm-clock">
<span class="bell"></span>
<span class="arrow-small"></span>
</div>
</body>
</html>
@keyframes rotate {
to {
transform: rotate(360deg);
}
}
.arrow-small {
animation-name: rotate;
animation-duration: 1s;
}
示例
动画延迟,其二
理论
我们来准备第二个动画,下一步我们会为它设置一个延迟
目标
创建一个动画
ding
,包含如下关键帧:33%
:translateX(-15px)
66%
:translateX(15px)
然后将其分配给 .bell
,持续 1s
。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Animation delay: animation-delay, step 2</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch2.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="mechanical">
<div class="alarm-clock">
<span class="bell"></span>
<span class="arrow-small"></span>
</div>
</body>
</html>
@keyframes rotate {
to {
transform: rotate(360deg);
}
}
.arrow-small {
animation-name: rotate;
animation-duration: 1s;
}
@keyframes ding {
33% {
transform: translateX(-15px);
}
66% {
transform: translateX(15px)
}
}
.bell {
animation-name: ding;
animation-duration: 1s;
}
示例
动画延迟,其三
理论
animation-delay
用于设置动画延迟,语法与 animation-duration
相同。
举例来说,如果我们设置延迟 10s
,动画不会立即开始播放,而是 10 秒之后才开始播放。
我们来完成之前的动画吧,让指针转一圈后铃才开始震动。
目标
为铃铛 .bell
设置如下动画:
1s
延迟后开始播放,持续
100ms
,重复播放次数:
10
。
实战
<!DOCTYPE html>
<html lang="en">
<head>
<title>Animation delay: animation-delay, step 3</title>
<meta charset="utf-8">
<link rel="stylesheet" href="epoch2.css">
<link rel="stylesheet" href="style.css">
</head>
<body class="mechanical">
<div class="alarm-clock">
<span class="bell"></span>
<span class="arrow-small"></span>
</div>
</body>
</html>
.bell {
animation-name: ding;
animation-duration: 1s;
animation-duration: 100ms;
animation-iteration-count: 10;
animation-delay: 1s;
}
.arrow-small {
animation-name: rotate;
animation-duration: 1s;
}
@keyframes rotate {
to {
transform: rotate(360deg);
}
}
@keyframes ding {
33% {
transform: translateX(-15px);
}
66% {
transform: translateX(15px);
}
}