CSS学习(13)CSS变形

304 阅读18分钟

前言

  • 请简述一下 CSS3 中新增的变形如何使用?

变形介绍

CSS2.1 中的页面都是静态的,多年来,Web 设计师依赖于图片、Flash 或者 JavaScript 才能完成修改页面的外观。CSS3 改变了设计师这种思维,借助 CSS3 可以轻松的倾斜、缩放、移动以及翻转元素。

2012 年 9 月,W3C 组织发布了 CSS3 变形工作草案。允许 CSS 把元素变成 2D 或者 3D 空间,这其实就是 CSS3 的 2D 变形和 3D 变形。

CSS3 变形是一些效果的集合,比如平移、旋转、缩放和倾斜效果,每个效果通过变形函数(transform function)来实现。在此之前,要想实现这些效果,必须依赖图片、Flash 或者 JavaScript 才能完成,而现在仅仅使用纯 CSS 就能够实现,大大的提高了开发效率以及页面的执行效率。

变形效果要通过变形函数来实现,语法如下:

transform: none|transform-functions;

那么 CSS3 中为我们提供了哪些变形函数呢?

这里我们整体可以划分出 3 大类:

  • 具有 X/Y 的函数:translateX、translateY、sclaeX、scaleY、skewX、skewY
  • 2D 变形函数:translate、sclae、rotate、skew、matrix
  • 3D 变形函数:rotateX、rotateY、rotate3d、translateZ、translate3d、scaleZ、scale3d、matrix3d

此时,你可能已经做好了逐一击破每个变形函数的思想准备了。

别急,在介绍每个变形函数之前,我们先来了解一下变形相关的属性。

变形属性

transform

transform 属性是 CSS3 中非常重要的一个属性,它允许我们通过 CSS 来控制元素的 2D 或者 3D 转换。语法如下:

transform: none|transform-functions;

取值说明:

  • none:不进行任何转换。
  • transform-functions:一个或多个转换函数,以空格分隔。

例如:

div {
  transform: rotate(45deg);
}

上面的代码中,我们设置了 transform 属性,属性值为 rotate(45deg),表示将元素顺时针旋转 45 度。

transform-origin

transform-origin 属性可以改变元素变形的原点,语法如下:

transform-origin: x-axis y-axis z-axis;

取值说明:

  • x-axis:定义变形原点的横坐标,可以是长度值、百分比、left、center、right。
  • y-axis:定义变形原点的纵坐标,可以是长度值、百分比、top、center、bottom。
  • z-axis:定义变形原点的 z 轴坐标,可以是长度值。

例如:

div {
  transform-origin: 50% 50%;
}

上面的代码中,我们设置了 transform-origin 属性,属性值为 50% 50%,表示将元素变形的原点设置在元素的中心位置。

下面我们实战看一下具体的使用方式:

<div></div>
div {
  width: 150px;
  height: 150px;
  margin: 50px;
  background-color: blue;
  transition: all 1s;
}

div:hover {
  transform: rotate(45deg);
}

效果如下:

20240711-184316.gif

上面的代码中,我们设置 div 鼠标 hover 的时候进行变形,旋转(transform: rotate(45deg);) 45 度,为了更加平滑,我们加入了 transition 过渡效果。

我们观察整个元素的旋转中心点,是在元素的最中央。

接下来我们可以使用 transform-origin 来修改这个中心点的位置。例如:

div {
  width: 150px;
  height: 150px;
  margin: 50px;
  background-color: blue;
  transition: all 1s;
  transform-origin: left top;
}

效果如下:

20240711-184606.gif

在上面的代码中,我们增加了 transform-origin: left top; 这行代码,修改了元素的中心点位置为 left、top,也就是左上角。可以看到因为元素的中心点位置发生了变化,旋转的方式也随之发生了改变。

transform-style

transform-style 属性可以指定元素的子元素是位于 3D 空间还是 2D 平面内,语法如下:

transform-style: flat|preserve-3d;

取值说明:

  • flat:所有子元素在 2D 平面内呈现。
  • preserve-3d:所有子元素在 3D 空间内呈现。

例如:

div {
  transform-style: preserve-3d;
}

上面的代码中,我们设置了 transform-style 属性,属性值为 preserve-3d,表示将元素的子元素在 3D 空间内呈现。

下面我们实战看一下具体的使用方式:

<div class="box">
  <div class="up"></div>
  <div class="down"></div>
  <div class="left"></div>
  <div class="right"></div>
  <div class="front"></div>
  <div class="back"></div>
</div>
.box {
  width: 100px;
  height: 100px;
  border: 1px solid black;  
  position: relative;
  margin: 150px;
  transform-style: preserve-3d;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 1s;
  animation: rotate 5s linear infinite;
}
.box>div {
  width: 100px;
  height: 100px;
  position: absolute;
  text-align: center;
  line-height: 100px;
}
.up {
  background-color: red;
  transform: translateY(-50px) rotateX(90deg);
}
.down {
  background-color: green;
  transform: translateY(50px) rotateX(-90deg);
}
.left {
  background-color: blue;
  transform: translateX(-50px) rotateY(90deg);
}
.right {
  background-color: yellow;
  transform: translateX(50px) rotateY(-90deg);
}
.front {
  background-color: pink;
  transform: translateZ(50px);
}
.back {
  background-color: orange;
  transform: translateZ(-50px);
}
@keyframes rotate {
  0% {
    transform: rotateY(0deg) rotateX(0deg);
  }
  100% {
    transform: rotateY(360deg) rotateX(360deg);
  }
}

效果如下:

20240712-144622.gif

在上面的代码中,我们创建了一个立方体,通过 transform-style: preserve-3d; 将子元素在 3D 空间内呈现,然后通过 transform 属性将子元素进行位移和旋转,从而形成了一个立方体。

如果将 transform-style 属性设置为 flat,那么子元素将在 2D 平面内呈现,效果如下:

20240712-144743.gif

怎么样?是不是非常直观,一下子就知道 transform-style 属性的作用是什么了。该属性就是指定子元素是在 3D 空间还是 2D 平面中显示。

perspective

perspective 属性可以指定观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。z>0 的三维元素比正常大,而 z<0 时则比正常小,大小程度由该属性的值决定。

简单理解,就是视距,用来设置用户和元素 3D 空间 Z 平面之间的距离。而其效应由他的值来决定,值越小,用户与 3D 空间 Z 平面距离越近,视觉效果更令人印象深刻;反之,值越大,用户与 3D 空间 Z 平面距离越远,视觉效果就很小。

注意当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本身。

语法如下:

perspective: none|<length>;

取值说明:

  • none:默认值,表示没有透视效果。
  • :指定观察者与 z=0 平面的距离,单位可以是 px、em 等。

例如:

.box {
  perspective: 500px;
}

上面的代码中,我们设置了 perspective 属性,属性值为 500px,表示观察者与 z=0 平面的距离为 500px。

使用示例

screenshot-20240712-151354.png

具体例子可参考developer.mozilla.org/zh-CN/docs/…

perspective-origin

perspective-origin 属性可以指定透视效果的原点,即观察者与 z=0 平面之间的连线与视景体近裁剪面的交点。

语法如下:

perspective-origin: [ | | left | center | right ] [ | | top | center | bottom ]?;

取值说明:

  • left:观察者与 z=0 平面之间的连线与视景体近裁剪面的交点在元素左边。
  • center:观察者与 z=0 平面之间的连线与视景体近裁剪面的交点在元素中间。
  • right:观察者与 z=0 平面之间的连线与视景体近裁剪面的交点在元素右边。
  • top:观察者与 z=0 平面之间的连线与视景体近裁剪面的交点在元素顶部。
  • bottom:观察者与 z=0 平面之间的连线与视景体近裁剪面的交点在元素底部。

例如:

.box {
  perspective-origin: 50% 50%;
}

上面的代码中,我们设置了 perspective-origin 属性,属性值为 50% 50%,表示观察者与 z=0 平面之间的连线与视景体近裁剪面的交点在元素中间。

示例

screenshot-20240712-151354.png

具体例子可参考developer.mozilla.org/zh-CN/docs/…

backface-visibility

backface-visibility 属性可以指定元素背面是否可见。

语法如下:

backface-visibility: visible|hidden;

取值说明:

  • visible:默认值,表示元素背面可见。
  • hidden:表示元素背面不可见。

例如:

.box {
  backface-visibility: hidden;
}

上面的代码中,我们设置了 backface-visibility 属性,属性值为 hidden,表示元素背面不可见。

示例

<div class="container">
  <div class="item"></div>
</div>
.container {
  margin: 150px;
  perspective: 1000px;
}

.item {
  width: 100px;
  height: 100px;
  background-color: red;
  backface-visibility: hidden;
  animation: rotateAnimation 5s infinite;
}
@keyframes rotateAnimation {
  0%{
    transform: rotateY(0deg);
  }
  100%{
    transform: rotateY(360deg);
  }
}

20240712-171244.gif

在上面的代码中,我们在子元素 div.item 上设置了 backface-visibility: hidden,当此元素旋转 180 度到背面时,我们可以发现此时是无法看到背面的。

2D 变形

介绍完 CSS3 中变形的相关属性后,接下来我们就该来看一下具体的变形函数了。

整个 CSS3 为我们提供了相当丰富的变形函数,有 2D 的,有 3D 的。这里我们先来看 2D 的变形函数。

2D 位移

2D 位移对应有 3 个变形函数,分别是 translate、translateX、translateY

用法也非常简单,translate 方法从其当前位置移动元素(根据为 X 轴和 Y 轴指定的参数)。

div { transform: translate(50px, 100px); }

上面的例子把 div 元素从其当前位置向右移动 50 个像素,并向下移动 100 个像素:效果如下:

20240712-172251.gif

2D 缩放

2D 缩放对应有 3 个变形函数,分别是 scale、scaleX、scaleY

用法也非常简单,scale 方法用于缩放某个元素的大小。scale 方法需要两个参数,分别代表宽度和高度。如果只指定一个参数,那么宽度与高度相等。

div { transform: scale(2, 4); }

上面的例子把 div 元素的宽度放大为原来的 2 倍,高度放大为原来的 4 倍:效果如下:

20240712-172615.gif

2D 旋转

2D 旋转对应有 1 个变形函数,分别是 rotate

用法也非常简单,rotate 方法在二维空间内对元素进行旋转,其语法如下:

div { transform: rotate(45deg); }

上面的例子把 div 元素顺时针旋转 45 度:效果如下:

20240712-172802.gif

2D 倾斜

2D 倾斜对应有 3 个变形函数,分别是 skew、skewX、skewY

用法也非常简单,skew 方法用于沿着 X 和 Y 轴对元素进行倾斜变换。skew 方法需要两个参数,分别代表 X 轴和 Y 轴的倾斜角度。如果只指定一个参数,那么 Y 轴的倾斜角度为 0 度。

div { transform: skew(30deg, 20deg); }

上面的例子把 div 元素沿 X 轴倾斜 30 度,沿 Y 轴倾斜 20 度:效果如下:

20240712-173017.gif

2D 矩阵

虽然 CSS3 为我们提供了上述的变形函数方便我们进行元素的变形操作,但是毕竟函数个数有限,有些效果是没有提供的,例如镜像翻转的效果。此时就轮到 2D 矩阵函数 matrix 登场了。

matrix 方法通过设置一个包含 6 个值的 2D 变换矩阵 来定义一个 2D 变换。这个方法允许你旋转、缩放、移动以及倾斜元素。

matrix 有六个参数:

matrix(a,b,c,d,e,f)

六个参数对应的矩阵:

screenshot-20240712-174754.png

这六个参数组成的矩阵与原坐标矩阵相乘计算坐标。计算方式如下:

screenshot-20240712-174718.png

x 和 y 是元素中每一个像素的初始原点的坐标,而 x'  和 y'  是通过矩阵变化后得到的新原点坐标。

x' = ax+cy+e,表示变换后的水平坐标

y' = bx+dy+f,表示变换后的垂直位置

在 CSS3 中,上面我们所介绍的所有 2D 变形函数都能够通过这个 matrix 矩阵函数来替代。

2D 矩阵 实现 2D 位移

我们首先来看通过矩阵实现偏移效果。

偏移效果前后 x、y 与 x'、y'  所对应的坐标公式为:

x' = x + 偏移量
y' = y + 偏移量

套用上面的公式(x' = ax+cy+ey' = bx+dy+f)那么各个参数的取值就应该是:

a = 1,c = 0, e = 偏移量
b = 0,d = 1, f = 偏移量

所以换成 matrix 函数就应该是:

matrix(1, 0, 0, 1, x 偏移量, y 偏移量)

下面来做一个测试:

<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}
div:hover{
  /* transform: translate(100px, 200px); */
  transform: matrix(1, 0, 0, 1, 100, 200);
}

在上面的示例中,使用 translate 和 matrix 两个变形函数的效果一致。

2D 矩阵 实现 2D 缩放

缩放效果前后 x、y 与 x'、y'  所对应的坐标公式为:

x' = x * 缩放比例
y' = y * 缩放比例

套用上面的公式(x' = ax+cy+ey' = bx+dy+f)那么各个参数的取值就应该是:

a = 缩放比例, c = 0, e = 0
b = 0, d = 缩放比例, f = 0

所以换成 matrix 函数就应该是:

matrix(缩放比例, 0, 0, 缩放比例, 0, 0)

下面来做一个测试:

<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}
div:hover{
  /* transform: scale(2, 4); */
  transform: matrix(2, 0, 0, 4, 0, 0);
}

在上面的示例中,使用 scale 和 matrix 两个变形函数的效果一致。

2D 矩阵 实现 2D 旋转

旋转效果前后 x、y 与 x'、y'  所对应的坐标公式为:

x' = x * cos(角度) - y * sin(角度)
y' = x * sin(角度) + y * cos(角度)

套用上面的公式(x' = ax+cy+ey' = bx+dy+f)那么各个参数的取值就应该是:

a = cos(角度), c = -sin(角度), e = 0
b = sin(角度), d = cos(角度), f = 0

所以换成 matrix 函数就应该是:

matrix(cos(角度), sin(角度), -sin(角度), cos(角度), 0, 0)

下面来做一个测试:

<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}
div:hover{
  /* transform: rotate(45deg); */
  transform: matrix(0.707, 0.707, -0.707, 0.707, 0, 0);
}

在上面的示例中,使用 rotate 和 matrix 两个变形函数的效果一致。

2D 矩阵 实现 2D 倾斜

倾斜效果前后 x、y 与 x'、y'  所对应的坐标公式为:

x' = x * tan(角度)
y' = y * tan(角度)

套用上面的公式(x' = ax+cy+ey' = bx+dy+f)那么各个参数的取值就应该是:

a = 1, c = tan(角度), e = 0
b = tan(角度), d = 1, f = 0

所以换成 matrix 函数就应该是:

matrix(1, tan(角度), tan(角度), 1, 0, 0)

下面来做一个测试:

<div></div>
div{
  width: 150px;
  height: 150px;
  background-color: red;
  margin: 150px;
  transition: all 1s;
}
div:hover{
  /* transform: skew(30deg, 20deg); */
  transform: matrix(1, 0.577, 0.577, 1, 0, 0);
}

在上面的示例中,使用 skew 和 matrix 两个变形函数的效果一致。

2D 矩阵 实现 水平镜像

镜像效果前后 x、y 与 x'、y'  所对应的坐标公式为:

x' = x * -1
y' = y * 1

套用上面的公式(x' = ax+cy+ey' = bx+dy+f)那么各个参数的取值就应该是:

a = -1, c = 0, e = 0
b = 0, d = 1, f = 0

所以换成 matrix 函数就应该是:

matrix(-1, 0, 0, 1, 0, 0)

下面来做一个测试:

<div class="container">
  <div class="item left"></div>
  <div class="item right"></div>
</div>
.container {
  width: 150px;
  height: 150px;
  margin: 150px;
  transition: all 1s;
  display: flex;
}
.container:hover {
  transform: matrix(-1, 0, 0, 1, 0, 0);
}
.item {
  flex: 1;
}
.left {
  background-color: red;
}
.right {
  background-color: green;
}

效果如下:

20240712-181137.gif

3D 变形

使用二维变形能够改变元素在水平和垂直轴线,然而还有一个轴沿着它,可以改变元素。使用三维变形,可以改变元素在 Z 轴位置。

3D 坐标系

screenshot-20240712-181632.png

三维变换使用基于二维变换的相同属性,如果熟悉二维变换就会发现,3D 变形的功能和 2D 变换的功能类似。CSS3 中的 3D 变换只要包含以下几类:

  • 3D 位移:包括 translateZ 和 translate3d 两个变形函数。
  • 3D 旋转:包括 rotateX、rotateY、rotateZ 和 rotate3d 这四个变形函数。
  • 3D 缩放:包括 scaleZ 和 sclae3d 两个变形函数。
  • 3D 矩阵:和 2D 变形一样,也有一个 3D 矩阵功能函数 matrix3d

3D 位移

translate3d() CSS 函数在 3D 空间内移动一个元素的位置。这个移动由一个三维向量来表达,分别表示他在三个方向上移动的距离。

transform: translate3d(tx, ty, tz);
  • tx:在 X 轴的位移距离。
  • ty:在 Y 轴的位移距离。
  • tz:在 Z 轴的位移距离。值越大,元素离观察者越近,值越小,元素离观察者越远

例如:

<div class="container">
  <div class="item"></div>
</div>
.container {
  width: 150px;
  height: 150px;
  margin: 150px;
  transition: all 1s;
  display: flex;
  perspective: 1000px;
}
.item {
  flex: 1;
  background-color: red;
  transition: all 2s;
}
.item:hover {
  transform: translate3d(200px, 100px, 500px);
}

在上面的代码中,我们设置 div.item 被 hover 的时候进行 3D 位移,也就是 X、Y、Z 轴同时进行移动。注意这里要设置父元素的透视效果,也就是设置 perspective 值,否则看不出 Z 轴的移动效果。效果如下:

20240715-154714.gif

3D 旋转

rotate3d() CSS 函数在 3D 空间中旋转一个元素。这个旋转由一个四元数表示,分别表示他在三个方向上旋转的角度。

transform: rotate3d(x, y, z, angle);
  • x:表示旋转轴的 X 轴坐标,可以是 0 到 1 之间的数值。
  • y:表示旋转轴的 Y 轴坐标,可以是 0 到 1 之间的数值。
  • z:表示旋转轴的 Z 轴坐标,可以是 0 到 1 之间的数值。
  • angle:表示旋转的角度,正值表示顺时针旋转,负值表示逆时针旋转。

例如:

  
<div class="container">
  <div class="item"></div>
</div>
.container {
  width: 150px;
  height: 150px;
  margin: 150px;
  transition: all 1s;
  display: flex;
  perspective: 1000px;
}
.item {
  flex: 1;
  background-color: red;
  transition: all 2s;
}
.item:hover {
  transform: rotate3d(1, 1, 0, 45deg);
}

在上面的代码中,我们设置 div.item 被 hover 的时候进行 3D 旋转,也就是 X、Y、Z 轴同时进行旋转。效果如下:

20240715-155400.gif

3D 缩放

scale3d() CSS 函数在 3D 空间中缩放一个元素的大小。这个缩放由一个三维向量表示,分别表示他在三个方向上缩放的比例。

transform: scale3d(sx, sy, sz);
  • sx:表示在 X 轴方向的缩放比例。
  • sy:表示在 Y 轴方向的缩放比例。
  • sz:表示在 Z 轴方向的缩放比例。

但是 scaleX 和 scaleY 变形效果很明显,但是 scaleZ 却基本看不出有什么效果。原因很简单,scaleZ 是 Z 轴上面的缩放,也就是厚度上面的变化,所以如果不是立方体结构,基本上是看不出来 Z 轴上面的缩放效果的。

一般来讲,我们不会将 scaleZ 和 scale3d 单独使用,因为 scaleZ 和 scale3d 这两个变形函数在单独使用时没有任何效果,需要配合其他的变形函数一起使用时才会有效果。

我么使用立方体进行举例

例如:

<div class="box">
  <div class="up"></div>
  <div class="down"></div>
  <div class="left"></div>
  <div class="right"></div>
  <div class="front"></div>
  <div class="back"></div>
</div>
.box {
  width: 100px;
  height: 100px;
  border: 1px solid black;  
  position: relative;
  margin: 150px;
  transform-style: preserve-3d;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 1s;
  transform: rotateY(45deg) rotateX(45deg);
}
.box:hover {
  transform: rotateY(45deg) rotateX(45deg) scaleZ(0.5);
}
.box>div {
  width: 100px;
  height: 100px;
  position: absolute;
  text-align: center;
  line-height: 100px;
}
.up {
  background-color: red;
  transform: translateY(-50px) rotateX(90deg);
}
.down {
  background-color: green;
  transform: translateY(50px) rotateX(-90deg);
}
.left {
  background-color: blue;
  transform: translateX(-50px) rotateY(90deg);
}
.right {
  background-color: yellow;
  transform: translateX(50px) rotateY(-90deg);
}
.front {
  background-color: pink;
  transform: translateZ(50px);
}
.back {
  background-color: orange;
  transform: translateZ(-50px);
}

效果如下:

20240715-155958.gif

3D 矩阵

CSS3 中的 3D 矩阵比 2D 矩阵复杂,从二维到三维,在矩阵里 33 变成 44,即 9 到 16。

对于 3D 矩阵而言,本质上很多东西与 2D 是一致的,只是复杂程度不一样而已。

其矩阵如下:

screenshot-20240715-162253.png

transform: matrix3d(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1);

这里举几个 3D 矩阵的例子:

translate3d(tx,ty,tz) 等价于 matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,tx,ty,tz,1)

image.png

scale3d(sx,sy,sz) 等价于 matrix3d(sx,0,0,0,0,sy,0,0,0,0,sz,0,0,0,0,1)

screenshot-20240715-163132.png

rotate3d(x,y,z,a) 这个涉及到数学知识,第四个参数 alpha 用于 sc 和 sq 中

screenshot-20240715-163203.png

当然除非是开发库函数,否则我严重怀疑是否会有人放着 rotate3d 不用,偏要去挑战用 matrix3d 模拟 rotate3d。

总结

请简述一下 CSS3 中新增的变形如何使用?

CSS3 中的变形分为 2D 变形和 3D 变形。

整体可以划分出 3 大类:

  • 具有 X/Y 的函数:translateX、translateY、sclaeX、scaleY、skewX、skewY
  • 2D 变形函数:translate、sclae、rotate、skew、matrix
  • 3D 变形函数:rotateX、rotateY、rotate3d、translateZ、translate3d、scaleZ、scale3d、matrix3d

另外,还有一些重要的变形属性,例如:

  • transform 属性
  • transform-origin 属性
  • transform-style 属性
  • perspective 属性
  • perspective-origin 属性
  • backface-visibility 属性