mirror of
https://github.com/qianguyihao/Web.git
synced 2024-11-01 13:34:46 +08:00
1440 lines
33 KiB
Markdown
1440 lines
33 KiB
Markdown
---
|
||
title: 12-CSS3属性详解:动画详解
|
||
publish: true
|
||
---
|
||
|
||
<ArticleTopAd></ArticleTopAd>
|
||
|
||
|
||
## 前言
|
||
|
||
本文主要内容:
|
||
|
||
- 过渡: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-小米商品详情过渡](https://github.com/qianguyihao/web-resource/blob/main/project/2018-02-08-%E5%B0%8F%E7%B1%B3%E5%95%86%E5%93%81%E8%AF%A6%E6%83%85%E8%BF%87%E6%B8%A1.rar)
|
||
|
||
|
||
|
||
|
||
## 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](https://github.com/qianguyihao/web-resource/blob/main/project/2018-02-09-fishes.rar)
|
||
|
||
## 我的公众号
|
||
|
||
想学习**更多技能**?不妨关注我的微信公众号:**千古壹号**(id:`qianguyihao`)。
|
||
|
||
扫一扫,你将发现另一个全新的世界,而这将是一场美丽的意外:
|
||
|
||
![](http://img.smyhvae.com/20190101.png)
|
||
|
||
|