Appearance
CSS 动画 第一部分:创建动画、分配动画、播放次数、方向、延迟
目录
Hello, animation!
理论
欢迎来到我们的 CSS 动画课程,这将是一次奇妙的探索!我们将走文明进化之路,征服深空。我们将在基础课程中对物体进行移动、旋转、变换。如果需要看更多的理论,请查阅 MDN 的文档;如果需要实践,我们就来看第一个任务吧!🚀
CSS 赋予你创建复杂动画的能力,你可以使用多种方式控制它们。一个 CSS 动画的描述分为两部分:一组关键帧 @keyframes 和动画参数。
下面是一个动画中简单的关键帧描述:
css
@keyframes stretching {
0% {
width: 100px;
}
100% {
width: 200px;
}
}这个例子中的动画被称作 stretching,描述了一个元素从初始状态变化到最终状态。这个动画可以被应用到任何元素上。使用动画时,你只需要添加两个属性到你的 CSS 中:动画名字和动画持续时间,并且给出相应的属性值。举个例子:
css
.button {
animation-name: stretching;
animation-duration: 1s;
}这段代码会将名为 stretching 的动画应用到所有拥有 button 类的元素上。这段代码的结果是,对应的元素的宽度会在 1 秒内从 100px 逐渐拉伸到 200px。
实战
html
<!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>css
@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% 两个关键帧。
实战
html
<!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>css
.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% 的值来定义的。
中间状态的关键帧是由百分数形式的值来定义的,下面是一个包含四个帧的动画:
css
@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)。
实战
html
<!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>css
.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 中的关键帧可以成组,把关键字放到逗号分隔的字符串中即可。我们看下面的例子:
css
@keyframes stretching {
0%, 50% {
width: 100px;
}
100% {
width: 200px;
}
}在这个例子中,前两个帧组成了一个组。对应的元素会在动画开始后宽度变为 100px,并且整个动画的前一半时间内都保持 100px 的宽度。然后,该元素的宽度会从 100px 变为 200px。
目标
- 将
50%的帧改为50%, 80%; - 将
50%, 80%中的动画改为transform: translateY(-50px)。
实战
html
<!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>css
.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。
实战
html
<!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>css
@keyframes rotate {
50% {
transform: rotate(360deg);
}
}
.stone-wheel {
animation-name: rotate;
animation-duration: 3s;
}示例
复杂动画,其二
理论
接下来我们看一下如何能为元素分配第二个同时播放的动画。
假设我们有如下两个动画:
css
@keyframes move {
to { left: 100px; }
}
@keyframes stretch {
to { width: 100px; }
}要给一个元素分配第二个动画,你需要添加它们的动画名称和持续时间,使用逗号分开。
css
.element {
animation-name: move, stretch;
animation-duration: 5s, 5s;
}在这个例子中,两个动画将同时开始,元素将会在 5 秒内同时移动和拉伸。
多重动画就像背景和阴影的 css 属性那样,传入多个值,用逗号分隔即可。
我们继续上一节的代码,为元素添加另一个动画吧。
目标
创建一个叫做
move的动画,包含如下关键帧:50%:bottom: 0px;100%:bottom: -50px。
添加第二个移动的动画,持续时间
6s,分配给.stone-wheel元素。
实战
html
<!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>css
@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)。让彗星也动起来。
实战
html
<!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>css
@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。然后让播放次数变为无限。
实战
html
<!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>css
@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。然后将两个齿轮的动画方向反转。
实战
html
<!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>css
@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,奇数次播放正常,偶数次播放反转。
css
.element {
animation-name: move;
animation-duration: 1s;
animation-iteration-count: 2;
animation-direction: alternate;
}在上面的例子中,move 动画将播放两次:第一次(奇数次)向前,第二次(偶数次)反过来。
如果设置为 alternate-reverse,奇数次将被反转,偶数次正常播放。
我们在下面的例子中看看这个属性是如何生效的。
目标
将两个齿轮的播放次数都设置为
2,设置交替方向播放,
设置反向交替方向播放。
实战
html
<!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>css
@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。
实战
html
<!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>css
@keyframes rotate {
to {
transform: rotate(360deg);
}
}
.arrow-small {
animation-name: rotate;
animation-duration: 1s;
}示例
动画延迟,其二
理论
我们来准备第二个动画,下一步我们会为它设置一个延迟
目标
创建一个动画
ding,包含如下关键帧:33%:translateX(-15px)66%:translateX(15px)
然后将其分配给 .bell,持续 1s。
实战
html
<!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>css
@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。
实战
html
<!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>css
.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);
}
}