# CSS3教程 - 14 变形

CSS3 中的变形 (Transforms))允许对元素进行各种图形上的转换,例如旋转、缩放、倾斜和位移,而不会更改元素在文档流中的位置。变形通常用于创建动画效果或在页面上实现交互式效果。

CSS3 中的 transform 属性支持四种基本的变形:平移 (Translation)、旋转 (Rotation)、缩放 (Scaling)、和倾斜 (Skewing),这些变形可以单独使用,也可以组合使用。

# 14.1 平移

# 1 平移的使用

语法:

transform: translateX(y);  /* 沿着 x 轴方向平移元素 */
/* 或者 */
transform: translateY(x);  /* 沿着 y 轴方向平移元素 */
/* 或者 */
transform: translate(x, y);  /* 同时沿着 x 轴和 y 轴平移元素 */
1
2
3
4
5

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>

      .box1 {
        transform: translateX(100px);  /* 右移100px */
        width: 100px;
        height: 100px;
        background-color: skyblue;
      }

      .box2 {
        width: 100px;
        height: 100px;
        background-color: pink;
      }
      
    </style>
  </head>

  <body>
    <div class="box1"></div>
    <div class="box2"></div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • 上面对 box1 右移 100px;
  • 变形不会改变元素在文档流中的位置,所以对 box2 没有影响;

显示如下,蓝色的 box1 右移了:


下面看一下 y 轴的平移:

<!DOCTYPE html>
<html>
  <head>
    <style>

      .box1 {
        transform: translateX(50px) translateY(50px);  /* 右移、下移100px */
        width: 100px;
        height: 100px;
        background-color: skyblue;
      }

      .box2 {
        width: 100px;
        height: 100px;
        background-color: pink;
      }
      
    </style>
  </head>

  <body>
    <div class="box1"></div>
    <div class="box2"></div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • 上面让 box1 右移和下移了 50px;
  • 也可以写为 transform: translate(50px, 50px);

显示如下:

可以看到对 box2 没有任何影响。

# 2 水平垂直居中

在前面让子元素在父元素中水平垂直居中有如下方式:

  1. 绝对定位的方式

    /* 这种居中方式,只适用于子元素的大小确定的情况,子元素尺寸为auto时候是不行的,会拉伸元素尺寸 */
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    margin: auto;
    
    1
    2
    3
    4
    5
    6
    7
  2. table-cell的方式

    /* table-cell的方式具有一定局限性,块元素是不行的 */
    display: table-cell;
    vertical-align: middle;
    text-align: center;
    
    1
    2
    3
    4

下面介绍一种新的水平垂直居中方式。

平移的距离可以使用百分比,表示是相对于元素自身的尺寸,X轴方向的平移相对于元素的宽度,Y轴方向上的平移相对于元素的高度。

通过这个特性,可以实现元素水平和垂直方向的居中。如下:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .outer {
        width: 300px;
        height: 300px;
        position: relative;  /* 父相子绝,父元素相对定位 */

        background-color: skyblue;
      }

      .inner {
        position: absolute;   /* 父相子绝,子元素绝对定位 */
        left: 50%;  /* 让子元素在包含块中右移父元素的宽度的一半 */
        top: 50%;  /* 让子元素在包含块中下移父元素的高度的一半 */
        transform: translateX(-50%) translateY(-50%);   /* 上面的操作会让子元素的左上角移动到了父元素的中心点,这里将子元素拉回自身元素一半的尺寸 */
        background-color: lightpink;
      }
    </style>
  </head>

  <body>
    <div class="outer">
      <div class="inner">foooor</div>
    </div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  • 首先父相子绝,父元素开启相对定位,子元素开启绝对定位,然后将子元素 lefttop 设置为 50%,那么子元素会右移和下移到父元素(包含块)的中心点位置,也就是子元素的左上角(起点)在父元素的中心点,所以需要将子元素水平和垂直方向上拉回子元素一半的距离,所以这里使用平移 50% ,也就是子元素向左、向上平移子元素 50% 的距离。
  • 这种居中方式,子元素的尺寸为 auto,也能实现居中。

显示如下:

# 3 浮出效果

我们经常会在网页中看到,将鼠标悬浮到指定的模块上,模块有浮出的效果,该如何实现呢?

实现思路:鼠标悬浮的时候,添加背景,并将元素向上移动。

实现如下:

<!DOCTYPE html>
<html>
  <head>
    <style>
      div {
        width: 200px;
        height: 200px;
        background-color: silver;
        margin: 30px auto;
        transition: all 0.3s;   /* 添加动画效果 */
      }

      div:hover {
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);  /* 添加阴影 */
        transform: translateY(-5px);  /* 在Y轴上向上移动 */
      }
    </style>
  </head>

  <body>
    <div class="box1"></div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • 在鼠标悬浮的时候,添加阴影,并将元素向上平移,然后添加一个动画即可。

# 4 Z轴平移

Z轴是垂直于屏幕的,在Z轴平移,调整的是元素和人眼之间的距离,平移距离越大,元素离人越近,元素显示也会变大(近大远小)。

它是属于3D的立体效果,默认情况下网页是不支持透视的(近大远小),如果需要看见效果必须要设置网页的视距。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        perspective: 800px;  /* 设置视距 */
      }

      .box1 {
        width: 100px;
        height: 100px;
        background-color: lightgray;
        margin: 100px auto;
        transition: all 0.3s;
      }

      .box1:hover {
        box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
        transform: translateZ(400px);   /* 沿着Z轴移动400像素 */
      }
    </style>
  </head>

  <body>
    <div class="box1"></div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  • 首先通过 perspective: 800px; 设置视距为800像素,然后通过 transform: translateZ(400px); 沿着 Z 轴方向平移400元素;也就是说一开始没平移的时候,相当于人眼距离元素800像素,然后沿着Z轴移动400像素,此时人眼距离元素为 800 - 400 = 400 像素,所以看元素应该是平移前的两倍大了。如果设置为 translateZ(800px) ,视距又是800像素,那么相当于把元素贴你脸上了,就无线大了。
  • perspective 推荐为 600 ~ 1200 像素,根据实际需要设置。

显示如下:

# 14.2 旋转

旋转主要使用 rotate() 函数来对元素进行旋转。旋转操作可以让元素围绕一个中心点进行旋转,旋转角度可以是正值或负值,表示顺时针或逆时针旋转。

# 1 旋转的使用

语法:

transform: rotateX(angle);  /* 绕 X 轴旋转,表现为元素上下翻转 */
/* 或者 */
transform: rotateY(angle);  /* 绕 Y 轴旋转,表现为元素左右翻转 */
/* 或者 */
transform: rotateZ(angle);  /* 绕 Z 轴旋转,表现为元素在平面内的旋转 */
/* 或者 */
transform: rotate(angle);   /* 绕 Z 轴旋转,表现为元素在平面内的旋转 */
1
2
3
4
5
6
7
  • angle:指定旋转的角度,通常使用度数(deg)、弧度(rad)、圈数(turn)等单位。常用的单位是 deg(度)。例如rotate(90deg) 表示顺时针旋转 90 度;rotate(-45deg):表示逆时针旋转 45 度。rotate(π / 2):表示顺时针旋转 90 度(π / 2 弧度)。rotate(1turn) 表示顺时针旋转一圈,等于 360 度;rotate(-0.5turn) 表示逆时针旋转半圈,等于 -180 度。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        perspective: 800px;  /* 设置视距 */
      }

      .box1 {
        width: 100px;
        height: 100px;
        background-color: lightgray;
        margin: 100px auto;
        transform: rotateZ(20deg);  /* 沿着Z轴旋转20度 */
      }
    </style>
  </head>

  <body>
    <div class="box1">foooor</div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  • 上面将 box1 沿着 Z 轴旋转了 20 度。

显示如下:

再举个栗子:沿着 X 轴旋转 45 度:

transform: rotateX(45deg);  /* 沿着Z轴旋转45度 */
1

显示如下:

上面是设置了 perspective ,所以沿着 X 或 Y 轴旋转的时候,有透视效果(近大远小),如果不设置视距,就没有近大远小的透视效果了,那么上图的元素上边缘和下边缘将是一样宽的。


再举个栗子:当鼠标悬浮的时候,沿着 Y 轴旋转 180 度,并添加过渡动画:

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        perspective: 800px; /* 设置视距 */
      }

      .box1 {
        width: 150px;
        height: 150px;
        background-color: lightgray;
        margin: 100px auto;
        transition: all 0.3s;  /* 设置动画,0.3秒完成 */
      }

      .box1:hover {
        transform: rotateY(180deg);  /* 沿着Y轴旋转180度 */
      }
    </style>
  </head>

  <body>
    <div class="box1">foooor</div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • 上面设置鼠标悬浮的时候沿着 Y 轴旋转180度;并设置了 0.3 秒的过渡;

显示如下:

# 2 变形中心

默认情况下,旋转是围绕元素的 中心点 进行的。如果需要改变旋转中心点,可以使用 transform-origin 属性。

transform-origin 属性定义了旋转的中心点(即元素围绕哪个点旋转)。它的值可以是像素、百分比或者关键字。

语法:

transform-origin: x-axis y-axis;   /* 2D旋转,围绕Z轴旋转 */
/* 或者 */
transform-origin: x-axis y-axis z-axis;  /* 3D旋转,可以围绕X轴和Y轴旋转 */
1
2
3
  • x-axis:水平位置,可以是像素值、百分比值或关键字(left, center, right)。
  • y-axis:垂直位置,可以是像素值、百分比值或关键字(top, center, bottom)。
  • z-axis:深度位置,可以是像素值或百分比(通常不使用关键字)。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        perspective: 800px; /* 设置视距 */
      }

      .box1 {
        width: 100px;
        height: 100px;
        background-color: lightgray;
        margin: 100px auto;
        
        transition: all 0.3s;  /* 设置动画,0.3秒完成 */
        transform-origin: 0px 0px;   /* 旋转的中心点在左上角 */
      }

      .box1:hover {
        transform: rotate(45deg);  /* 沿着Z轴顺时针旋转45度 */
      }
    </style>
  </head>

  <body>
    <div class="box1">foooor</div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  • 上面设置旋转中心点为 (0,0) ,也就是左上角;当鼠标悬浮在 box1 的时候,就在Z轴围绕着左上角旋转。

显示如下:

# 14.3 缩放

对元素进行缩放,主要使用的函数是 scale()

# 1 缩放的使用

语法:

transform: scaleX(x);  /* 对X轴方向上进行缩放 */
transform: scaleY(y);  /* 对Y轴方向上进行缩放 */
transform: scale(x, y);  /* 对X轴和Y轴双方向进行缩放 */
transform: scaleZ(y);  /* 对Z轴方向上进行缩放 */
transform: scale3d(x, y, z);  /* 对X、Y、Z轴三个方向进行缩放 */
1
2
3
4
5
  • 在没有进行缩放的时候,x、y、z的值是 1。如果要放大,则设置值为大于 1 的数即可;如果要缩小,设置值为小于 1 的小数即可。

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .box1 {
        height: 200px;
        width: 200px;
        background-color: skyblue;
        margin: 200px auto;
        transition: all 0.3s;  /* 添加过渡效果 */
      }

      .box1:hover {
        transform: scaleX(2);
      }
    </style>
  </head>

  <body>
    <div class="box1">foooor</div>
  </body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • 上面在鼠标悬浮 box1 的时候,对 box1 进行 X 轴的 2 倍缩放。

显示如下:

Y 轴的缩放也是类似的,如果是 X 轴 Y 轴同时缩放,使用 scale(x, y) 即可。

但是此时对 Z 轴缩放是没有效果的,因为 Z 轴方向上,元素没有尺寸,Z 轴的缩放用的不多。

# 2 变形中心

在旋转的时候,通过 transform-origin 属性指定旋转中心,同样可以通过 transform-origin 属性可以指定缩放中心, transform-origin 就是用来指定变形原点的。

举个栗子,基于上面的代码,指定缩放中心:

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        perspective: 800px;
      }

      .box1 {
        height: 100px;
        width: 100px;
        background-color: skyblue;
        margin: 200px auto;
        transition: all 0.3s;  /* 过渡效果 */
        transform-origin: 0 0;  /* 变形的原点 */
      }

      .box1:hover {
        transform: scale(2, 2);  /* x、y轴缩放 */
      }
    </style>
  </head>

  <body>
    <div class="box1">foooor</div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  • 上面指定了 box1 的缩放原点为 0,0 ,也就是左上角,然后鼠标悬浮的时候,对 X 轴和 Y 轴进行两倍的放大。

显示如下:

# 14.4 变形组合使用

平移、旋转、缩放的变换是可以一起使用的。变换是按顺序进行的,因此后面的变换会影响前面的变换

举个栗子:

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        perspective: 800px;
      }

      .box1 {
        height: 100px;
        width: 100px;
        background-color: skyblue;
        margin: 200px auto;
        transition: all 0.5s;  /* 过渡效果 */
      }

      .box1:hover {
        transform: translateX(200px) rotate(180deg) scale(2, 2);  /* 同时变形 */
      }
    </style>
  </head>

  <body>
    <div class="box1">foooor</div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  • 在上面的代码中,鼠标悬浮的时候,会同时进行平移、旋转和缩放。

显示如下:

需要注意变换的顺序,变换是按顺序进行的,因此后面的变换会影响前面的变换,所以上面的平移是放到最前面的,如果放到最后面,那么元素被旋转后,自身坐标系也被旋转了,会发现元素向左平移了,


# 14.5 练习-立方体

下面通过变形实现一个立方体,立方体的每个面使用不同的图片。

最终效果:

实现思路:首先定义一个外部的元素,在外部的元素中放六个子 div 元素,并给每个子 div 设置不同的背景,充当立方体的六个面。然后父相子绝,父元素采用相对定位,子元素采用绝对定位,那么六个子元素就重叠了。旋转和平移各个div,分别作为左右、上下、前后的面,这样就实现了。

这里父元素需要用到一个属性 transform-style: preserve-3d; 让元素的 子元素 能够 保留三维变换,即它们也会在三维空间中进行变换。默认情况下,子元素的变换会被应用到其父元素的平面上,也就是说,子元素将被 “拉平”,不受父元素三维变换的影响。通过使用 preserve-3d,可以确保子元素保持其在 3D 空间中的位置。

代码如下:

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        perspective: 800px;
      }

      .cube {
        height: 200px;
        width: 200px;
        margin: 200px auto;
        position: relative;  /* 父相子绝 */
        transform-style: preserve-3d;  /* 设置3d变形效果 */
        animation: cube-rotate 12s infinite linear;   /* 设置动画效果 */
      }

      .cube div {
        height: 200px;
        width: 200px;
        background-size: cover;
        background-position: center;
        position: absolute;  /* 父相子绝 */
        opacity: 0.9;  /* 设置透明效果 */
      }

      .surface1 {
        background-image: url("/image/css3.webp");
        transform: translateX(-100px) rotateY(90deg);  /* 左边的面 */
      }

      .surface2 {
        background-image: url("/image/html5.webp");
        transform: translateX(100px) rotateY(90deg);  /* 右边的面 */
      }

      .surface3 {
        background-image: url("/image/javascript.webp");
        transform: translateY(-100px) rotateX(90deg);  /* 上边的面 */
      }

      .surface4 {
        background-image: url("/image/git.webp");
        transform: translateY(100px) rotateX(90deg);  /* 下边的面 */
      }

      .surface5 {
        background-image: url("/image/java.webp");
        transform: translateZ(100px);  /* 前边的面 */
      }

      .surface6 {
        background-image: url("/image/vue3.webp");
        transform: rotateX(180deg) translateZ(100px);  /* 后边的面 */
      }

      @keyframes cube-rotate {
        from {
          transform: rotateX(0) rotateY(0) rotateZ(0);
        }

        to {
          transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg);
        }
      }
    </style>
  </head>

  <body>
    <div class="cube">
      <div class="surface1"></div>
      <div class="surface2"></div>
      <div class="surface3"></div>
      <div class="surface4"></div>
      <div class="surface5"></div>
      <div class="surface6"></div>
    </div>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79