Webcourse/07-HTML5和CSS3/05-CSS3属性详解:动画详解.md
2019-02-03 18:06:24 +08:00

1453 lines
33 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

> 本文最初发表于[博客园](),并在[GitHub](https://github.com/smyhvae/Web)上持续更新**前端的系列文章**。欢迎在GitHub上关注我一起入门和进阶前端。
> 以下是正文。
## 前言
本文主要内容:
- 过渡transition
- 2D 转换 transform
- 3D 转换 transform
- 动画animation
## 过渡transition
`transition`的中文含义是**过渡**。过渡是CSS3中具有颠覆性的一个特征可以实现元素**不同状态间的平滑过渡**(补间动画),经常用来制作动画效果。
- 补间动画:自动完成从起始状态到终止状态的的过渡。不用管中间的状态。
- 帧动画:通过一帧一帧的画面按照固定顺序和速度播放。如电影胶片。
参考链接:[补间动画基础](http://mux.alimama.com/posts/1009)
transition 包括以下属性:
- `transition-property: all;` 如果希望所有的属性都发生过渡就使用all。
- `transition-duration: 1s;` 过渡的持续时间。
- `transition-timing-function: linear;` 运动曲线。属性值可以是:
- `linear` 线性
- `ease` 减速
- `ease-in` 加速
- `ease-out` 减速
- `ease-in-out` 先加速后减速
- `transition-delay: 1s;` 过渡延迟。多长时间后再执行这个过渡动画。
上面的四个属性也可以写成**综合属性**
```javascript
transition: 让哪些属性进行过度 过渡的持续时间 运动曲线 延迟时间;
transition: all 3s linear 0s;
```
其中,`transition-property`这个属性是尤其需要注意的,不同的属性值有不同的现象。我们来示范一下。
如果设置 `transition-property: width`,意思是只让盒子的宽度在变化时进行过渡。效果如下:
![](http://img.smyhvae.com/20180208_1440.gif)
如果设置 `transition-property: all`,意思是让盒子的所有属性(包括宽度、背景色等)在变化时都进行过渡。效果如下:
![](http://img.smyhvae.com/20180208_1445.gif)
### 案例:小米商品详情
代码:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>CSS 过渡</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #eeeeee;
}
.content {
width: 800px;
height: 320px;
padding-left: 20px;
margin: 80px auto;
}
.item {
width: 230px;
height: 300px;
text-align: center;
margin-right: 20px;
background-color: #FFF;
float: left;
position: relative;
top: 0;
overflow: hidden; /* 让溢出的内容隐藏起来。意思是让下方的橙色方形先躲起来 */
transition: all .5s; /* 从最初到鼠标悬停时的过渡 */
}
.item img {
margin-top: 30px;
}
.item .desc {
position: absolute;
left: 0;
bottom: -80px;
width: 100%;
height: 80px;
background-color: #ff6700;
transition: all .5s;
}
/* 鼠标悬停时,让 item 整体往上移动5px且加一点阴影 */
.item:hover {
top: -5px;
box-shadow: 0 0 15px #AAA;
}
/* 鼠标悬停时,让下方的橙色方形现身 */
.item:hover .desc {
bottom: 0;
}
</style>
</head>
<body>
<div class="content">
<div class="item">
<img src="./images/1.png" alt="">
</div>
<div class="item">
<img src="./images/2.png" alt="">
<span class="desc"></span>
</div>
<div class="item">
<img src="./images/3.jpg" alt="">
<span class="desc"></span>
</div>
</div>
</body>
</html>
```
效果如下:
![](http://img.smyhvae.com/20180208_1500.gif)
动画效果录制的比较差,但真实体验还是可以的。
工程文件:
- [2018-02-08-小米商品详情过渡](http://download.csdn.net/download/smyhvae/10245871)
## 2D 转换
**转换**是 CSS3 中具有颠覆性的一个特征,可以实现元素的**位移、旋转、变形、缩放**,甚至支持矩阵方式。
转换再配合过渡和动画,可以取代大量早期只能靠 Flash 才可以实现的效果。
在 CSS3 当中,通过 `transform` 转换来实现 2D 转换或者 3D 转换。
- 2D转换包括缩放、移动、旋转。
我们依次来讲解。
### 1、缩放`scale`
格式:
```javascript
transform: scale(x, y);
transform: scale(2, 0.5);
```
参数解释: x表示水平方向的缩放倍数。y表示垂直方向的缩放倍数。如果只写一个值就是等比例缩放。
取值大于1表示放大小于1表示缩小。不能为百分比。
格式举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box {
width: 1000px;
margin: 100px auto;
}
.box div {
width: 300px;
height: 150px;
background-color: pink;
float: left;
margin-right: 15px;
color: white;
text-align: center;
font: 400 30px/150px “宋体”;
}
.box .box2 {
background-color: green;
transition: all 1s;
}
.box .box2:hover {
/*width: 500px;*/
/*height: 400px;*/
background-color: yellowgreen;
/* transform: css3中用于做变换的属性
scale(x,y):缩放 */
transform: scale(2, 0.5);
}
</style>
</head>
<body>
<div class="box">
<div class="box1">1</div>
<div class="box2">2</div>
<div class="box3">3</div>
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_1551.gif)
上图可以看到,给 box1 设置 2D 转换,并不会把兄弟元素挤走。
### 2、位移translate
格式:
```javascript
transform: translate(水平位移, 垂直位移);
transform: translate(-50%, -50%);
```
参数解释:
- 参数为百分比,相对于自身移动。
- 正值:向右和向下。 负值:向左和向上。如果只写一个值,则表示水平移动。
格式举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box {
width: 1000px;
margin: 100px auto;
}
.box > div {
width: 300px;
height: 150px;
border: 1px solid #000;
background-color: red;
float: left;
margin-right: 30px;
}
div:nth-child(2) {
background-color: pink;
transition: all 1s;
}
/* translate:(水平位移,垂直位移)*/
div:nth-child(2):hover {
transform: translate(-50%, -50%);
}
</style>
</head>
<body>
<div class="box">
<div class="box1">1</div>
<div class="box2">2</div>
<div class="box3">3</div>
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_1600.gif)
上图中,因为我在操作的时候,鼠标悬停后,立即进行了略微的移动,所以产生了两次动画。正确的效果应该是下面这样的:
![](http://img.smyhvae.com/20180208_1605.gif)
**应用:**让绝对定位中的盒子在父亲里居中
我们知道,如果想让一个**标准流中的盒子在父亲里居中**(水平方向看),可以将其设置`margin: 0 auto`属性。
可如果盒子是绝对定位的,此时已经脱标了,如果还想让其居中(位于父亲的正中间),可以这样做:
```
div {
width: 600px;
height: 60px;
position: absolute; 绝对定位的盒子
left: 50%; 首先,让左边线居中
top: 0;
margin-left: -300px; 然后向左移动宽度600px的一半
}
```
如上方代码所示我们先让这个宽度为600px的盒子左边线居中然后向左移动宽度600px的一半就达到效果了。
![](http://img.smyhvae.com/20180116_1356.png)
现在,我们还可以利用偏移 translate 来做,这也是比较推荐的写法:
```javascript
div {
width: 600px;
height: 60px;
background-color: red;
position: absolute; 绝对定位的盒子
left: 50%; 首先让左边线居中
top: 0;
transform: translate(-50%); 然后利用translate往左走自己宽度的一半推荐写法
}
```
### 3、旋转rotate
格式:
```javascript
transform: rotate(角度);
transform: rotate(45deg);
```
参数解释:正值 顺时针;负值:逆时针。
举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box {
width: 200px;
height: 200px;
background-color: red;
margin: 50px auto;
color: #fff;
font-size: 50px;
transition: all 2s; /* 过渡:让盒子在进行 transform 转换的时候,有个过渡期 */
}
/* rotate角度旋转 */
.box:hover {
transform: rotate(-405deg); /* 鼠标悬停时,让盒子进行旋转 */
}
</style>
</head>
<body>
<div class="box">1</div>
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_1630.gif)
注意,上方代码中,我们给盒子设置了 transform 中的 rotate 旋转,但同时还要给盒子设置 transition 过渡。如果没有这行过渡的代码,旋转会直接一步到位,效果如下:(不是我们期望的效果)
![](http://img.smyhvae.com/20180208_1635.gif)
**案例1**小火箭
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
html,body{
height:100%;
}
body{
background-color: #DE8910;
}
.rocket{
position: absolute;
left:100px;
top:600px;
height: 120px;
transform:translate(-200px ,200px) rotate(45deg);
transition:all 1s ease-in;
}
body:hover .rocket{
transform:translate(500px,-500px) rotate(45deg);
}
</style>
</head>
<body>
<img class="rocket" src="images/rocket.png" alt=""/>
</body>
</html>
```
上方代码中,我们将 transform 的两个小属性合并起来写了。
小火箭图片的url<http://img.smyhvae.com/20180208-rocket.png>
**案例2**扑克牌
rotate 旋转时,默认是以盒子的正中心为坐标原点的。如果想**改变旋转的坐标原点**,可以用`transform-origin`属性。格式如下:
```javascript
transform-origin: 水平坐标 垂直坐标;
transform-origin: 50px 50px;
transform-origin: center bottom; //旋转时,以盒子底部的中心为坐标原点
```
我们来看一下 rotate 结合 transform-origin 的用法举例。
代码如下:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
/*background-color: #eee;*/
}
.box {
width: 300px;
height: 440px;
margin: 100px auto;
position: relative;
}
img {
width: 100%;
transition: all 1.5s;
position: absolute; /* 既然扑克牌是叠在一起的,那就都用绝对定位 */
left: 0;
top: 0;
transform-origin: center bottom; /*旋转时,以盒子底部的中心为坐标原点*/
box-shadow: 0 0 3px 0 #666;
}
.box:hover img:nth-child(6) {
transform: rotate(-10deg);
}
.box:hover img:nth-child(5) {
transform: rotate(-20deg);
}
.box:hover img:nth-child(4) {
transform: rotate(-30deg);
}
.box:hover img:nth-child(3) {
transform: rotate(-40deg);
}
.box:hover img:nth-child(2) {
transform: rotate(-50deg);
}
.box:hover img:nth-child(1) {
transform: rotate(-60deg);
}
.box:hover img:nth-child(8) {
transform: rotate(10deg);
}
.box:hover img:nth-child(9) {
transform: rotate(20deg);
}
.box:hover img:nth-child(10) {
transform: rotate(30deg);
}
.box:hover img:nth-child(11) {
transform: rotate(40deg);
}
.box:hover img:nth-child(12) {
transform: rotate(50deg);
}
.box:hover img:nth-child(13) {
transform: rotate(60deg);
}
</style>
</head>
<body>
<div class="box">
<img src="images/pk1.png"/>
<img src="images/pk2.png"/>
<img src="images/pk1.png"/>
<img src="images/pk2.png"/>
<img src="images/pk1.png"/>
<img src="images/pk2.png"/>
<img src="images/pk1.png"/>
<img src="images/pk2.png"/>
<img src="images/pk1.png"/>
<img src="images/pk2.png"/>
<img src="images/pk1.png"/>
<img src="images/pk2.png"/>
<img src="images/pk1.png"/>
</div>
</body>
</html>
```
效果如下:
![](http://img.smyhvae.com/20180208_1650.gif)
### 4、倾斜
暂略。
## 3D 转换
### 1、旋转rotateX、rotateY、rotateZ
**3D坐标系左手坐标系**
![](http://img.smyhvae.com/20180208_2010.png)
如上图所示伸出左手让拇指和食指成“L”形大拇指向右食指向上中指指向前方。拇指、食指和中指分别代表X、Y、Z轴的正方向这样我们就建立了一个左手坐标系。
浏览器的这个平面是X轴、Y轴垂直于浏览器的平面是Z轴。
**旋转的方向:(左手法则)**
左手握住旋转轴,竖起拇指指向旋转轴的**正方向**,正向就是**其余手指卷曲的方向**。
从上面这句话我们也能看出所有的3d旋转对着正方向去看都是顺时针旋转。
**格式:**
```javascript
transform: rotateX(360deg); //绕 X 轴旋转360度
transform: rotateY(360deg); //绕 Y 轴旋转360度
transform: rotateZ(360deg); //绕 Z 轴旋转360度
```
**格式举例:**
1rotateX 举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.rotateX {
width: 300px;
height: 226px;
margin: 200px auto;
/* 透视 :加给变换的父盒子*/
/* 设置的是用户的眼睛距离 平面的距离*/
/* 透视效果只是视觉上的呈现并不是正真的3d*/
perspective: 110px;
}
img {
/* 过渡*/
transition: transform 2s;
}
/* 所有的3d旋转对着正方向去看都是顺时针旋转*/
.rotateX:hover img {
transform: rotateX(360deg);
}
</style>
</head>
<body>
<div class="rotateX">
<img src="images/x.jpg" alt=""/>
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_2025.gif)
上方代码中我们最好加个透视的属性方能看到3D的效果没有这个属性的话图片旋转的时候像是压瘪了一样。
而且,透视的是要加给图片的父元素 div方能生效。我们在后面会讲解透视属性。
2rotateY 举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.rotateY {
width: 237px;
height: 300px;
margin: 100px auto;
/* 透视 */
perspective: 150px;
}
img {
transition: all 2s; /* 过渡 */
}
.rotateY:hover img {
transform: rotateY(360deg);
}
</style>
</head>
<body>
<div class="rotateY">
<img src="images/y.jpg" alt=""/>
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_2030.gif)
3rotateZ 举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.rotateZ {
width: 330px;
height: 227px;
margin: 100px auto;
/* 透视*/
perspective: 200px;
}
img {
transition: all 1s;
}
.rotateZ:hover img {
transform: rotateZ(360deg);
}
</style>
</head>
<body>
<div class="rotateZ">
<img src="images/z.jpg" alt=""/>
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_2035.gif)
**案例:**百度钱包
现在有下面这张图片素材:
![](http://img.smyhvae.com/20180208_2055.png)
要求做成下面这种效果:
![](http://img.smyhvae.com/20180208_2100.gif)
上面这张图片素材其实用的是精灵图。实现的代码如下:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
background-color: cornflowerblue;
}
.box {
width: 300px;
height: 300px;
/*border: 1px solid #000;*/
margin: 50px auto;
position: relative;
}
.box > div {
width: 100%;
height: 100%;
position: absolute;
/*border: 1px solid #000;*/
border-radius: 50%;
transition: all 2s;
backface-visibility: hidden;
}
.box1 {
background: url(images/bg.png) left 0 no-repeat; /*默认显示图片的左半边*/
}
.box2 {
background: url(images/bg.png) right 0 no-repeat;
transform: rotateY(180deg); /*让图片的右半边默认时旋转180度就可以暂时隐藏起来*/
}
.box:hover .box1 {
transform: rotateY(180deg); /*让图片的左半边转消失*/
}
.box:hover .box2 {
transform: rotateY(0deg); /*让图片的左半边转出现*/
}
</style>
</head>
<body>
<div class="box">
<div class="box1"></div>
<div class="box2"></div>
</div>
</body>
</html>
```
### 2、移动translateX、translateY、translateZ
**格式:**
```javascript
transform: translateX(100px); //沿着 X 轴移动
transform: translateY(360px); //沿着 Y 轴移动
transform: translateZ(360px); //沿着 Z 轴移动
```
**格式举例:**
1translateX 举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box {
width: 200px;
height: 200px;
background: green;
transition: all 1s;
}
.box:hover {
transform: translateX(100px);
}
</style>
</head>
<body>
<div class="box">
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_2036.gif)
2translateY 举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box {
width: 200px;
height: 200px;
background: green;
transition: all 1s;
}
.box:hover {
transform: translateY(100px);
}
</style>
</head>
<body>
<div class="box">
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_2037.gif)
3translateZ 举例:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body {
/* 给box的父元素加透视效果*/
perspective: 1000px;
}
.box {
width: 250px;
height: 250px;
background: green;
transition: all 1s;
margin: 200px auto
}
.box:hover {
/* translateZ必须配合透视来使用*/
transform: translateZ(400px);
}
</style>
</head>
<body>
<div class="box">
</div>
</body>
</html>
```
效果:
![](http://img.smyhvae.com/20180208_2040.gif)
上方代码中如果不加透视属性是看不到translateZ的效果的。
### 3、透视perspective
电脑显示屏是一个 2D 平面图像之所以具有立体感3D效果其实只是一种视觉呈现通过透视可以实现此目的。
透视可以将一个2D平面在转换的过程当中呈现3D效果。但仅仅只是视觉呈现出3d 效果并不是正真的3d。
格式有两种写法:
- 作为一个属性设置给父元素作用于所有3D转换的子元素
- 作为 transform 属性的一个值,做用于元素自身。
### 4、3D呈现transform-style
3D元素构建是指某个图形是由多个元素构成的可以给这些元素的**父元素**设置`transform-style: preserve-3d`来使其变成一个真正的3D图形。属性值可以如下
```javascript
transform-style: preserve-3d; //让 子盒子 位于三维空间里
transform-style: flat; //让子盒子位于此元素所在的平面内(子盒子被扁平化)
```
**案例:**立方体
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box {
width: 250px;
height: 250px;
border: 1px dashed red;
margin: 100px auto;
position: relative;
border-radius: 50%;
/* 让子盒子保持3d效果*/
transform-style: preserve-3d;
/*transform:rotateX(30deg) rotateY(-30deg);*/
animation: gun 8s linear infinite;
}
.box > div {
width: 100%;
height: 100%;
position: absolute;
text-align: center;
line-height: 250px;
font-size: 60px;
color: #daa520;
}
.left {
background-color: rgba(255, 0, 0, 0.3);
/* 变换中心*/
transform-origin: left;
/* 变换*/
transform: rotateY(90deg) translateX(-125px);
}
.right {
background: rgba(0, 0, 255, 0.3);
transform-origin: right;
/* 变换*/
transform: rotateY(90deg) translateX(125px);
}
.forward {
background: rgba(255, 255, 0, 0.3);
transform: translateZ(125px);
}
.back {
background: rgba(0, 255, 255, 0.3);
transform: translateZ(-125px);
}
.up {
background: rgba(255, 0, 255, 0.3);
transform: rotateX(90deg) translateZ(125px);
}
.down {
background: rgba(99, 66, 33, 0.3);
transform: rotateX(-90deg) translateZ(125px);
}
@keyframes gun {
0% {
transform: rotateX(0deg) rotateY(0deg);
}
100% {
transform: rotateX(360deg) rotateY(360deg);
}
}
</style>
</head>
<body>
<div class="box">
<div class="up"></div>
<div class="down"></div>
<div class="left"></div>
<div class="right"></div>
<div class="forward"></div>
<div class="back"></div>
</div>
</body>
</html>
```
## 动画
动画是CSS3中具有颠覆性的特征可通过设置**多个节点** 来精确控制一个或一组动画,常用来实现**复杂**的动画效果。
### 1、定义动画的步骤
1通过@keyframes定义动画
2将这段动画通过百分比分割成多个节点然后各节点中分别定义各属性
3在指定元素里通过 `animation` 属性调用动画。
之前,我们在 js 中定义一个函数的时候,是先定义,再调用:
```javascript
js 定义函数
function fun(){ 函数体 }
调用
fun();
```
同样,我们在 CSS3 中**定义动画**的时候,也是**先定义,再调用**
```javascript
定义动画
@keyframes 动画名{
from{ 初始状态 }
to{ 结束状态 }
}
调用
animation: 动画名称 持续时间
```
其中animation属性的格式如下
```javascript
animation: 定义的动画名称 持续时间 执行次数 是否反向 运动曲线 延迟执行(infinite 表示无限次)
animation: move1 1s alternate linear 3;
animation: move2 4s;
```
**定义动画的格式举例:**
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.box {
width: 100px;
height: 100px;
margin: 100px;
background-color: red;
/* 调用动画*/
/* animation: 动画名称 持续时间 执行次数 是否反向 运动曲线 延迟执行。infinite 表示无限次*/
/*animation: move 1s alternate linear 3;*/
animation: move2 4s;
}
/* 方式一:定义一组动画*/
@keyframes move1 {
from {
transform: translateX(0px) rotate(0deg);
}
to {
transform: translateX(500px) rotate(555deg);
}
}
/* 方式二:定义多组动画*/
@keyframes move2 {
0% {
transform: translateX(0px) translateY(0px);
background-color: red;
border-radius: 0;
}
25% {
transform: translateX(500px) translateY(0px);
}
/*动画执行到 50% 的时候,背景色变成绿色,形状变成圆形*/
50% {
/* 虽然两个方向都有translate但其实只是Y轴上移动了200px。
因为X轴的500px是相对最开始的原点来说的。可以理解成此时的 translateX 是保存了之前的位移 */
transform: translateX(500px) translateY(200px);
background-color: green;
border-radius: 50%;
}
75% {
transform: translateX(0px) translateY(200px);
}
/*动画执行到 100% 的时候,背景色还原为红色,形状还原为正方形*/
100% {
/*坐标归零,表示回到原点。*/
transform: translateX(0px) translateY(0px);
background-color: red;
border-radius: 0;
}
}
</style>
</head>
<body>
<div class="box">
</div>
</body>
</html>
```
注意好好看代码中的注释。
效果如下:
![](http://img.smyhvae.com/20180209_1001.gif)
### 2、动画属性
我们刚刚在调用动画时animation属性的格式如下
animation属性的格式如下
```javascript
animation: 定义的动画名称 持续时间 执行次数 是否反向 运动曲线 延迟执行(infinite 表示无限次)
animation: move1 1s alternate linear 3;
animation: move2 4s;
```
可以看出,这里的 animation 是综合属性,接下来,我们把这个综合属性拆分看看。
1动画名称
```javascript
animation-name: move;
```
2执行一次动画的持续时间
```javascript
animation-duration: 4s;
```
备注:上面两个属性,是必选项,且顺序固定。
3动画的执行次数
```javascript
animation-iteration-count: 1; //iteration的含义表示迭代
```
属性值`infinite`表示无数次。
3动画的方向
```javascript
animation-direction: alternate;
```
属性值normal 正常alternate 反向。
4动画延迟执行
```javascript
animation-delay: 1s;
```
5设置动画结束时盒子的状态
```javascript
animation-fill-mode: forwards;
```
属性值: forwards保持动画结束后的状态默认 backwards动画结束后回到最初的状态。
6运动曲线
```
animation-timing-function: ease-in;
```
属性值可以是linear ease-in-out steps()等。
注意,如果把属性值写成**` steps()`**,则表示动画**不是连续执行**,而是间断地分成几步执行。我们接下来专门讲一下属性值 `steps()`
### steps()的效果
我们还是拿上面的例子来举例,如果在调用动画时,我们写成:
```javascript
animation: move2 4s steps(2);
```
效果如下:
![](http://img.smyhvae.com/20180209_1020.gif)
有了属性值 `steps()`,我们就可以作出很多不连续地动画效果。比如时钟;再比如,通过多张静态的鱼,作出一张游动的鱼。
**step()举例:**时钟的简易模型
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
div {
width: 3px;
height: 200px;
background-color: #000;
margin: 100px auto;
transform-origin: center bottom; /* 旋转的中心点是底部 */
animation: myClock 60s steps(60) infinite;
}
@keyframes myClock {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div></div>
</body>
</html>
```
上方代码我们通过一个黑色的长条div旋转360度耗时60s分成60步完成。即可实现。
效果如下:
![](http://img.smyhvae.com/20180209_1030.gif)
### 动画举例:摆动的鱼
现在,我们要做下面这种效果:
![](http://img.smyhvae.com/20180209_1245.gif)
PS图片的url是<http://img.smyhvae.com/20180209_1245.gif>,图片较大,如无法观看,可在浏览器中单独打开。
为了作出上面这种效果,要分成两步。
**1第一步**:让鱼在原地摆动
鱼在原地摆动并不是一张 gif动图她其实是由很多张静态图间隔地播放一秒钟播放完毕就可以了
![](http://img.smyhvae.com/20180209_shark.png)
上面这张大图的尺寸是:宽 509 px、高 2160 px。
我们可以理解成,每一帧的尺寸是:宽 509 px、高 270 px。`270 * 8 = 2160`。让上面这张大图,在一秒内从 0px 的位置往上移动2160px分成8步来移动。就可以实现了。
代码是:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.shark {
width: 509px;
height: 270px; /*盒子的宽高是一帧的宽高*/
border: 1px solid #000;
margin: 100px auto;
background: url(images/shark.png) left top; /* 让图片一开始位于 0 px的位置 */
animation: sharkRun 1s steps(8) infinite; /* 一秒之内,从顶部移动到底部,分八帧, */
}
@keyframes sharkRun {
0% {
}
/* 270 * 8 = 2160 */
100% {
background-position: left -2160px; /* 动画结束时,让图片位于最底部 */
}
}
</style>
</head>
<body>
<div class="sharkBox">
<div class="shark"></div>
</div>
</div>
</body>
</html>
```
效果如下:
![](http://img.smyhvae.com/20180209_1250.gif)
我们不妨把上面的动画的持续时间从`1s`改成 `8s`,就可以看到动画的慢镜头:
![](http://img.smyhvae.com/20180209_1330.gif)
这下,你应该恍然大悟了。
**2第二步**:让鱼所在的盒子向前移动。
实现的原理也很简单,我们在上一步中已经让`shark`这个盒子实现了原地摇摆,现在,让 shark 所在的父盒子 `sharkBox`向前移动,即可。完整版代码是:
```html
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
.shark {
width: 509px;
height: 270px; /* 盒子的宽高是一帧的宽高 */
border: 1px solid #000;
margin: 100px auto;
background: url(images/shark.png) left top; /* 让图片一开始位于 0 px的位置 */
animation: sharkRun 1s steps(8) infinite; /* 一秒之内,从顶部移动到底部,分八帧 */
}
/* 鱼所在的父盒子 */
.sharkBox {
width: 509px;
height: 270px;
animation: sharkBoxRun 20s linear infinite;
}
@keyframes sharkRun {
0% {
}
/* 270 * 8 = 2160 */
100% {
background-position: left -2160px; /* 动画结束时,让图片位于最底部 */
}
}
@keyframes sharkBoxRun {
0% {
transform: translateX(-600px);
}
100% {
transform: translateX(3000px);
}
}
</style>
</head>
<body>
<div class="sharkBox">
<div class="shark"></div>
</div>
</div>
</body>
</html>
```
![](http://img.smyhvae.com/20180209_1350.gif)
大功告成。
工程文件如下:
- [2018-02-09-fishes.rar](http://download.csdn.net/download/smyhvae/10255540)
## 我的公众号
想学习<font color=#0000ff>**代码之外的技能**</font>?不妨关注我的微信公众号:**千古壹号**id`qianguyihao`)。
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
![](http://img.smyhvae.com/2016040102.jpg)