前言
在开始介绍CSS变形动画之前,可以先了解一下学习了它之后能做什么,有什么用,这样你看这篇文章可能会有一些动力。
学习了CSS变形动画后,你可以为你的页面做出很多炫酷的效果,如一个3D的魔方,一个很酷的旋转菜单等等。
在本章节中将会采用大量的实例进行演示,相信你如果看完这篇文章后写出的页面会更加的吸引眼球。
基础知识
坐标系统
首先我们要学习的变形动画,想达到在上图中出现的3D效果单纯的X与Y两个轴是实现不了的,还需要加入一条纵深轴,即Y轴的参与才有一个3D的视觉感受。
那么如何来理解X,Y,Z这三条轴的关系呢?可以看一下下面这张图。
- X轴代表水平轴
- Y轴代表垂直轴
- Z轴代表纵深轴
X和Y轴都非常好理解,怎么理解这个Z轴呢?
CSS的中文名称叫做层叠样式表,那么它肯定是一层一层的。之前学习过z-index就是用来设置层的优先级,优先级越高越在上面,也可以理解为离我们肉眼越近,它把优先级低的层给盖住了,所以Z轴可以理解为我们观察的视角与被观察物体之间的一条轴。
Z轴数值越大,说明观测距离越远。
Z轴的数值可以无限大,所以设置的时候一定要小心。
变形操作
可以使用transform规则控制元素的变形操作,包括元素移动、旋转、倾斜、3D转换等等。
下表中是CSS提供的变形动作,在接下来的学习中将会对一个变形动作进行详解。
选项 | 说明 |
---|---|
none | 定义不进行转换。 |
translate(x,y) | 定义 2D 转换。 |
translate3d(x,y,z) | 定义 3D 转换。 |
translateX(x) | 定义转换,只是用 X 轴的值。 |
translateY(y) | 定义转换,只是用 Y 轴的值。 |
translateZ(z) | 定义 3D 转换,只是用 Z 轴的值。 |
scale(x,y) | 定义 2D 缩放转换。 |
scale3d(x,y,z) | 定义 3D 缩放转换。 |
scaleX(x) | 通过设置 X 轴的值来定义缩放转换。 |
scaleY(y) | 通过设置 Y 轴的值来定义缩放转换。 |
scaleZ(z) | 通过设置 Z 轴的值来定义 3D 缩放转换。 |
rotate(angle) | 定义 2D 旋转,在参数中规定角度。 |
rotate3d(x,y,z,angle) | 定义 3D 旋转。 |
rotateX(angle) | 定义沿着 X 轴的 3D 旋转。 |
rotateY(angle) | 定义沿着 Y 轴的 3D 旋转。 |
rotateZ(angle) | 定义沿着 Z 轴的 3D 旋转。 |
skew(x-angle,y-angle) | 定义沿着 X 和 Y 轴的 2D 倾斜转换。 |
skewX(angle) | 定义沿着 X 轴的 2D 倾斜转换。 |
skewY(angle) | 定义沿着 Y 轴的 2D 倾斜转换。 |
perspective(n) | 为 3D 转换元素定义透视视图。 |
变形叠加
这其实是一个坑点,在使用变形中一定要注意,重复对元素设置变形操作时只在元素的原形态上操作。
我们可以先看一下下面的案例,不懂代码没关系,懂这个意思就行了。
默认处理
下面设置了两次移动,并不会移动550px 而是只移动50px。
我们在元素中先设置了右移500px,鼠标放上去时再往右移动50px,可是下面却出现了向左移动的场景,这是因为对div进行了位置居中处理,它必须要按照之前居中的位置进行50px的移动。而不是按照居中后设置的500px的地方再进行向右移动50px。
上面这句话有点绕,总之。上面设置了,位置改变了,下面再设置,不会按照已改变的位置进行变化,而是按照原位置。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
}
body {
height: 100vh;
width: 100vw;
background-color: aliceblue;
display: flex;
justify-content: center;
align-items: center;
}
div {
width: 200px;
height: 200px;
background-color: blueviolet;
/* 意思就是说按x轴移动500px */
transform: translateX(500px);
/* 过渡时间2s */
transition: 2s;
}
div:hover {
/* 意思就是说按x轴移动50px */
transform: translateX(50px);
}
</style>
</head>
<body>
<div></div>
</body>
</html>
伪类叠加
还是设置两次移动,如果移动的方向都一样,且伪类设置的移动比原本的移动多一点,就在原本的基础上直接进行变形,而不用再找开始位置了。
我们还是拿上面的案例,只不过伪类移动的数值将50px改为600px,比第一次设置大100px,那么此时他就不会再往左走,而是直接在原有基础上进行叠加,向右移动100px。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
list-style: none;
}
body {
height: 100vh;
width: 100vw;
background-color: aliceblue;
display: flex;
justify-content: center;
align-items: center;
}
div {
width: 200px;
height: 200px;
background-color: blueviolet;
/* 意思就是说按x轴移动500px */
transform: translateX(500px);
/* 过渡时间2s */
transition: 2s;
}
div:hover {
/* 意思就是说按x轴移动600px */
transform: translateX(600px);
}
</style>
</head>
<body>
<div></div>
</body>
</html>
内联元素
内联元素即行级元素,inline元素是不能参与变形的,将其转为 inline-block 或 block 以及弹性元素时才可以产生变化效果。
:hover伪类
鼠标移动到某一元素上发生的用户行为。
当该行为出现时,我们可以为它指定一些参数的改变。
如下,改变颜色。
:target伪类
意思就是说你点击一个<a>,该<a>标签中的href指向的锚点标签会发生变化。
点击第一个<a>元素,与之相对的锚点元素发生变化。
点击第二个<a>元素,与第一个<a>元素相对的锚点变化停止,与第二个<a>元素相对的锚点发生变化。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
}
div {
width: 200px;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 2em;
}
div:nth-child(1) {
background: red;
}
div:nth-child(2) {
background: blue;
}
#div-1:target {
background-color: green;
}
#div-2:target {
background-color: black;
}
</style>
</head>
<body>
<div id="div-1">原本颜色:红</div>
<div id="div-2">原本颜色:蓝</div>
<a href="#div-1">让div-1变绿</a>
<a href="#div-2">让div-2变黑</a>
</body>
</html>
最后注意一点
事件元素上放过渡时间,:hover上放具体的事件,如移动,旋转,倾斜等操作。
如果你设置了移动却将过渡时间放在了:hover里面,那么就会出现下面这种情况。
可以看见,直勾勾的就回来了,这种效果显然不是我们想要的。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
main {
width: 400px;
height: 200px;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
/* 为了设置第一个div的中心点,所以这里设置一个定位,让子元素的绝对定位参照该元素进行偏移 */
position: relative;
}
div:first-child {
height: 8px;
width: 8px;
background-color: black;
z-index: 1;
border-radius: 50%;
/* 脱离文档流并居中 */
position: absolute;
left: 50%;
top: 50%;
margin-left: -4px;
margin-top: -4px;
}
div:last-child {
height: 100px;
width: 100px;
background-color: blueviolet;
/* 过渡时间1s,应该放这里,而不是:hover上面 */
/* transition: 1s; */
}
div:last-child:hover {
transform: translateX(100px);
}
</style>
</head>
<body>
<main>
<div></div>
<div></div>
</main>
</body>
</html>
移动元素
- 沿X轴移动时正值向右移动、负值向左移动
- 沿Y轴移动时正值向下移动、负值向上移动
- 如果使用百分数将控制元素的原尺寸计算百分比然后移动
- 可同时设置多个值,解析器会从左向右依次执行
- 变形是在原基础上更改,即第二次设置值时不是在第一次值上变化
translateX
控制元素在X轴上的移动,正值向右、负值向左。
如,我们下面设置translateX(100px),过渡时间为1s。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
main {
width: 400px;
height: 200px;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
/* 为了设置第一个div的中心点,所以这里设置一个定位,让子元素的绝对定位参照该元素进行偏移 */
position: relative;
}
div:first-child {
height: 8px;
width: 8px;
background-color: black;
z-index: 1;
border-radius: 50%;
/* 脱离文档流并居中 */
position: absolute;
left: 50%;
top: 50%;
margin-left: -4px;
margin-top: -4px;
}
div:last-child {
height: 100px;
width: 100px;
background-color: blueviolet;
/* 过渡时间1s,应该放这里,而不是:hover上面 */
transition: 1s;
}
div:last-child:hover {
transform: translateX(100px);
}
</style>
</head>
<body>
<main>
<div></div>
<div></div>
</main>
</body>
</html>
translateY
控制元素在X轴上的移动,正值向下、负值向上。
如,我们下面设置translateY(100px),过渡时间为1s。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
main {
width: 200px;
height: 400px;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
/* 为了设置第一个div的中心点,所以这里设置一个定位,让子元素的绝对定位参照该元素进行偏移 */
position: relative;
}
div:first-child {
height: 8px;
width: 8px;
background-color: black;
z-index: 1;
border-radius: 50%;
/* 脱离文档流并居中 */
position: absolute;
left: 50%;
top: 50%;
margin-left: -4px;
margin-top: -4px;
}
div:last-child {
height: 100px;
width: 100px;
background-color: blueviolet;
/* 过渡时间1s,应该放这里,而不是:hover上面 */
transition: 1s;
}
div:last-child:hover {
transform: translateY(100px);
}
</style>
</head>
<body>
<main>
<div></div>
<div></div>
</main>
</body>
</html>
translate
translate是translateX以及translateY的简写模式,第一个值控制X移动,第二个值控制Y移动。
一句话,设置X与Y轴的移动,注意,这个方法中不包含Z轴,因为一旦有Z轴参与就会变为3D效果。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
main {
width: 400px;
height: 400px;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
/* 为了设置第一个div的中心点,所以这里设置一个定位,让子元素的绝对定位参照该元素进行偏移 */
position: relative;
}
div:first-child {
height: 8px;
width: 8px;
background-color: black;
z-index: 1;
border-radius: 50%;
/* 脱离文档流并居中 */
position: absolute;
left: 50%;
top: 50%;
margin-left: -4px;
margin-top: -4px;
}
div:last-child {
height: 100px;
width: 100px;
background-color: blueviolet;
/* 过渡时间1s,应该放这里,而不是:hover上面 */
transition: 1s;
}
div:last-child:hover {
/* 先设置X轴,再设置Y轴 */
transform: translate(100px, 100px);
}
</style>
</head>
<body>
<main>
<div></div>
<div></div>
</main>
</body>
</html>
百分比移动
当要移动的元素宽高为100px时,如果使用50%进行移动,则代表移动50px。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
main {
width: 400px;
height: 400px;
border: 1px solid #ccc;
display: flex;
justify-content: center;
align-items: center;
/* 为了设置第一个div的中心点,所以这里设置一个定位,让子元素的绝对定位参照该元素进行偏移 */
position: relative;
}
div:first-child {
height: 8px;
width: 8px;
background-color: black;
z-index: 1;
border-radius: 50%;
/* 脱离文档流并居中 */
position: absolute;
left: 50%;
top: 50%;
margin-left: -4px;
margin-top: -4px;
}
div:last-child {
height: 100px;
width: 100px;
background-color: blueviolet;
/* 过渡时间1s,应该放这里,而不是:hover上面 */
transition: 1s;
}
div:last-child:hover {
/* 先设置X轴,再设置Y轴 */
transform: translate(50%, 50%);
}
</style>
</head>
<body>
<main>
<div></div>
<div></div>
</main>
</body>
</html>
元素居中
我们之前介绍过很多元素居中的方法,如定位操作,弹性盒模型,其实使用移动也可以达到元素居中的效果。
给你丢一套模板。
/* 让子元素脱离文档流并参照副父级元素偏移。这是定位+margin的居中方法 */
position: absolute;
left: 50%;
top: 50%;
/* left和top设置子元素宽高的负的50%就行 */
margin-left: -3px;
margin-top: -3px;
/* 这是弹性盒模型控制元素居中的方法 */
display: flex;
justify-content: center;
align-items: center;
/* 让子元素脱离文档流并参照副父级元素偏移。这是定位+移动的居中方法 */
position: absolute;
left: 50%;
top: 50%;
/* X和Y设置子元素宽高的负的50%就行 */
transform: translate(-50%, -50%);
translateZ
控制Z轴移动,正数向外(距离我们近)、负数向里移动(距离我们远)。因为Z轴是透视轴没有像X/Y一样的固定尺寸,所以不能使用百分数。
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
box-sizing: border-box;
}
body {