
> 本文最初发表于[博客园]()，并在[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度

```

**格式举例：**

（1）rotateX 举例：

```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，方能生效。我们在后面会讲解透视属性。

（2）rotateY 举例：

```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)

（3）rotateZ 举例：

```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 轴移动

```

**格式举例：**

（1）translateX 举例：

```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)

（2）translateY 举例：

```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)

（3）translateZ 举例：

```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 属性的一个值，做用于元素自身。

格式举例：

```css
perspective: 500px;
```

### 4、3D呈现（transform-style）

3D元素构建是指某个图形是由多个元素构成的，可以给这些元素的**父元素**设置`transform-style: preserve-3d`来使其变成一个真正的3D图形。属性值可以如下：

```css
	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)


## 我的公众号

想学习**代码之外的技能**？不妨关注我的微信公众号：**千古壹号**（id：`qianguyihao`）。

扫一扫，你将发现另一个全新的世界，而这将是一场美丽的意外：

![](http://img.smyhvae.com/20190101.png)


