Skip to content

CSS 变换:2D 与 3D 空间的魔法

魔术师在舞台上让物体旋转、漂浮、变大变小,观众为之惊叹。在网页世界中,CSS Transform(变换)赋予了我们类似的"魔法"——移动、旋转、缩放、倾斜元素,甚至在三维空间中操纵它们。与传统的定位和尺寸调整不同,变换不会影响文档流,却能创造出令人印象深刻的视觉效果。

什么是 CSS 变换?

CSS 变换允许你在二维或三维空间中修改元素的坐标空间,改变元素的位置、大小、角度和形状。关键特点:

  • 不影响布局:变换后的元素仍占据原始空间,不会推挤其他元素
  • 性能优异:现代浏览器使用 GPU 加速,动画流畅
  • 可组合:多个变换可以叠加使用
  • 可过渡:与 transition 完美配合,创造平滑动画

2D 变换:平面空间的操作

2D 变换在 X(水平)和 Y(垂直)两个轴上操作元素。

translate:平移元素

translate 移动元素的位置,但不改变其在文档流中的位置。

css
/* 沿 X 轴(水平)移动 */
.move-right {
  transform: translateX(50px); /* 向右移动 50px */
}

.move-left {
  transform: translateX(-30px); /* 向左移动 30px */
}

/* 沿 Y 轴(垂直)移动 */
.move-down {
  transform: translateY(20px); /* 向下移动 20px */
}

.move-up {
  transform: translateY(-40px); /* 向上移动 40px */
}

/* 同时在 X 和 Y 轴移动 */
.move-diagonal {
  transform: translate(30px, 20px); /* 向右30px,向下20px */
}

/* 使用百分比(相对于元素自身尺寸) */
.center-absolute {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* 居中技巧 */
}

为什么用 translate 而不是 position?

css
/* ❌ 使用 position:触发重排,性能较差 */
.box {
  position: relative;
  left: 50px;
  top: 20px;
}

/* ✅ 使用 transform:只触发合成,性能更好 */
.box {
  transform: translate(50px, 20px);
}

rotate:旋转元素

rotate 围绕一个点旋转元素,默认是元素的中心点。

css
/* 顺时针旋转 */
.rotate-clockwise {
  transform: rotate(45deg); /* 旋转45度 */
}

/* 逆时针旋转(负值) */
.rotate-counter {
  transform: rotate(-30deg);
}

/* 完整旋转 */
.spin {
  transform: rotate(360deg);
}

/* 使用其他单位 */
.rotate-radians {
  transform: rotate(1.57rad); /* 约90度(π/2) */
}

.rotate-turns {
  transform: rotate(0.5turn); /* 半圈,180度 */
}

实际应用:旋转箭头

css
.arrow {
  display: inline-block;
  transition: transform 0.3s ease;
}

.arrow.up {
  transform: rotate(0deg);
}

.arrow.right {
  transform: rotate(90deg);
}

.arrow.down {
  transform: rotate(180deg);
}

.arrow.left {
  transform: rotate(-90deg);
}

scale:缩放元素

scale 改变元素的大小,值为 1 时保持原始大小。

css
/* 均匀缩放 */
.zoom-in {
  transform: scale(1.5); /* 放大到150% */
}

.zoom-out {
  transform: scale(0.8); /* 缩小到80% */
}

/* X 轴缩放 */
.stretch-horizontal {
  transform: scaleX(2); /* 水平拉伸2倍 */
}

/* Y 轴缩放 */
.stretch-vertical {
  transform: scaleY(1.5); /* 垂直拉伸1.5倍 */
}

/* X 和 Y 不同缩放 */
.distort {
  transform: scale(1.5, 0.5); /* 宽度1.5倍,高度0.5倍 */
}

/* 镜像翻转 */
.flip-horizontal {
  transform: scaleX(-1); /* 水平翻转 */
}

.flip-vertical {
  transform: scaleY(-1); /* 垂直翻转 */
}

实际应用:悬停放大

css
.card {
  transition: transform 0.3s ease;
}

.card:hover {
  transform: scale(1.05); /* 悬停时放大5% */
}

/* 图片缩放(常见于图片画廊) */
.image-container {
  overflow: hidden;
}

.image-container img {
  display: block;
  width: 100%;
  transition: transform 0.5s ease;
}

.image-container:hover img {
  transform: scale(1.2);
}

skew:倾斜元素

skew 沿 X 或 Y 轴倾斜元素,创造斜切效果。

css
/* X 轴倾斜(左右拉伸) */
.skew-x {
  transform: skewX(15deg); /* 向右倾斜15度 */
}

/* Y 轴倾斜(上下拉伸) */
.skew-y {
  transform: skewY(-10deg); /* 向下倾斜10度 */
}

/* 同时倾斜 X 和 Y */
.skew-both {
  transform: skew(10deg, 5deg);
}

倾斜效果在实际中用得较少,但可以创造独特的装饰效果,如平行四边形按钮。

实际应用:平行四边形背景

css
.parallelogram {
  position: relative;
  padding: 15px 30px;
  color: white;
}

.parallelogram::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: #3498db;
  transform: skewX(-15deg);
  z-index: -1;
}

matrix:矩阵变换

matrix() 可以用一个函数表示所有 2D 变换,但通常只在高级场景或由工具生成时使用。

css
.matrix-transform {
  /* matrix(scaleX, skewY, skewX, scaleY, translateX, translateY) */
  transform: matrix(1, 0.5, -0.5, 1, 30, 20);
  /* 等同于组合 scale、skew 和 translate */
}

组合多个变换

多个变换可以在一个 transform 属性中组合,用空格分隔。

css
.combined {
  transform: translate(50px, 20px) rotate(45deg) scale(1.2);
  /* 先移动,再旋转,最后缩放 */
}

注意顺序很重要:变换从右到左应用(数学上的矩阵乘法顺序)。

css
/* 结果不同 */
.order-1 {
  transform: rotate(45deg) translateX(100px);
  /* 先旋转元素,然后沿旋转后的X轴移动 */
}

.order-2 {
  transform: translateX(100px) rotate(45deg);
  /* 先向右移动,然后原地旋转 */
}

大多数情况下,建议顺序:translaterotatescale

transform-origin:变换原点

默认情况下,变换围绕元素的中心点进行。transform-origin 可以改变这个原点。

css
/* 默认:中心点 */
.default-origin {
  transform-origin: center center; /* 或 50% 50% */
}

/* 左上角 */
.top-left-origin {
  transform-origin: top left; /* 或 0% 0% */
  transform: rotate(45deg); /* 围绕左上角旋转 */
}

/* 右下角 */
.bottom-right-origin {
  transform-origin: bottom right; /* 或 100% 100% */
}

/* 自定义位置 */
.custom-origin {
  transform-origin: 30% 70%;
}

/* 使用像素值 */
.pixel-origin {
  transform-origin: 50px 20px;
}

实际应用:门的开关效果

css
.door {
  width: 200px;
  height: 300px;
  background: #8b4513;
  transform-origin: left center; /* 左侧边缘为轴 */
  transition: transform 0.5s ease;
}

.door.open {
  transform: rotateY(90deg); /* 3D旋转,后面会讲 */
}

3D 变换:进入第三维度

3D 变换在 X、Y、Z 三个轴上操作元素,Z 轴垂直于屏幕。

perspective:透视距离

要看到 3D 效果,必须设置透视距离。这模拟了人眼到屏幕的距离。

css
/* 方法1:在父元素上设置 */
.container {
  perspective: 1000px; /* 透视距离1000px */
}

.child {
  transform: rotateY(45deg); /* 子元素才会有3D效果 */
}

/* 方法2:在 transform 中使用 */
.element {
  transform: perspective(1000px) rotateY(45deg);
}

透视距离的影响

  • 小值(300px-500px):夸张的透视,物体变形明显
  • 中值(800px-1200px):自然的透视,最常用
  • 大值(1500px+):微妙的透视,接近平行投影

translateZ 和 translate3d:Z 轴移动

css
/* Z 轴移动(接近或远离观察者) */
.move-closer {
  transform: translateZ(50px); /* 向前移动(变大) */
}

.move-away {
  transform: translateZ(-30px); /* 向后移动(变小) */
}

/* 3D 平移(同时指定 X, Y, Z) */
.move-3d {
  transform: translate3d(20px, 30px, 40px);
}

注意:单独使用 translateZ 不明显,需要配合 perspective 才能看到效果。

rotate3d:3D 旋转

css
/* X 轴旋转(上下翻转) */
.rotate-x {
  transform: rotateX(45deg);
}

/* Y 轴旋转(左右翻转) */
.rotate-y {
  transform: rotateY(60deg);
}

/* Z 轴旋转(平面旋转,等同于 rotate) */
.rotate-z {
  transform: rotateZ(30deg);
}

/* 围绕任意轴旋转:rotate3d(x, y, z, angle) */
.rotate-custom {
  transform: rotate3d(1, 1, 0, 45deg);
  /* 围绕向量(1,1,0)旋转45度 */
}

scale3d:3D 缩放

css
/* Z 轴缩放(厚度) */
.scale-z {
  transform: scaleZ(2); /* 配合其他3D变换才有意义 */
}

/* 3D 缩放 */
.scale-3d {
  transform: scale3d(1.5, 1.2, 0.8);
}

transform-style:保留 3D

默认情况下,子元素会被"压平"到父元素的 2D 平面。使用 transform-style: preserve-3d 可以保留 3D 空间。

css
.parent {
  perspective: 1000px;
  transform-style: preserve-3d; /* 关键:保留3D空间 */
}

.child {
  transform: rotateY(45deg) translateZ(50px);
  /* 在3D空间中变换 */
}

backface-visibility:背面可见性

当元素旋转超过 90 度时,会看到元素的"背面"。可以控制背面是否可见。

css
.card-front,
.card-back {
  backface-visibility: hidden; /* 背面不可见 */
}

.card-back {
  transform: rotateY(180deg); /* 背面默认反转180度 */
}

实战案例:3D 翻转卡片

创建一个悬停时翻转的卡片,前后两面不同内容。

html
<div class="flip-card">
  <div class="flip-card-inner">
    <div class="flip-card-front">
      <h3>Front Side</h3>
      <p>Hover to flip</p>
    </div>
    <div class="flip-card-back">
      <h3>Back Side</h3>
      <p>Hidden content revealed!</p>
    </div>
  </div>
</div>
css
.flip-card {
  width: 300px;
  height: 200px;
  perspective: 1000px; /* 透视距离 */
}

.flip-card-inner {
  width: 100%;
  height: 100%;
  position: relative;
  transition: transform 0.6s;
  transform-style: preserve-3d; /* 保留3D空间 */
}

.flip-card:hover .flip-card-inner {
  transform: rotateY(180deg); /* 翻转180度 */
}

.flip-card-front,
.flip-card-back {
  position: absolute;
  width: 100%;
  height: 100%;
  backface-visibility: hidden; /* 背面不可见 */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  padding: 20px;
}

.flip-card-front {
  background: linear-gradient(135deg, #667eea, #764ba2);
  color: white;
}

.flip-card-back {
  background: linear-gradient(135deg, #f093fb, #f5576c);
  color: white;
  transform: rotateY(180deg); /* 背面预先翻转 */
}

实战案例:3D 立方体

创建一个可旋转的 3D 立方体。

html
<div class="cube-container">
  <div class="cube">
    <div class="cube-face front">Front</div>
    <div class="cube-face back">Back</div>
    <div class="cube-face right">Right</div>
    <div class="cube-face left">Left</div>
    <div class="cube-face top">Top</div>
    <div class="cube-face bottom">Bottom</div>
  </div>
</div>
css
.cube-container {
  width: 200px;
  height: 200px;
  perspective: 1000px;
  margin: 100px auto;
}

.cube {
  width: 200px;
  height: 200px;
  position: relative;
  transform-style: preserve-3d;
  animation: rotateCube 10s infinite linear;
}

.cube-face {
  position: absolute;
  width: 200px;
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24px;
  font-weight: bold;
  color: white;
  opacity: 0.9;
  border: 2px solid rgba(255, 255, 255, 0.3);
}

.front {
  background: rgba(231, 76, 60, 0.8);
  transform: translateZ(100px);
}

.back {
  background: rgba(52, 152, 219, 0.8);
  transform: translateZ(-100px) rotateY(180deg);
}

.right {
  background: rgba(46, 204, 113, 0.8);
  transform: rotateY(90deg) translateZ(100px);
}

.left {
  background: rgba(243, 156, 18, 0.8);
  transform: rotateY(-90deg) translateZ(100px);
}

.top {
  background: rgba(155, 89, 182, 0.8);
  transform: rotateX(90deg) translateZ(100px);
}

.bottom {
  background: rgba(52, 73, 94, 0.8);
  transform: rotateX(-90deg) translateZ(100px);
}

@keyframes rotateCube {
  from {
    transform: rotateX(0deg) rotateY(0deg);
  }
  to {
    transform: rotateX(360deg) rotateY(360deg);
  }
}

实战案例:视差滚动效果

使用 translateZ 创建简单的视差效果。

html
<div class="parallax-container">
  <div class="parallax-layer background">Background</div>
  <div class="parallax-layer middle">Middle</div>
  <div class="parallax-layer foreground">Foreground</div>
</div>
css
.parallax-container {
  height: 100vh;
  overflow-x: hidden;
  overflow-y: scroll;
  perspective: 1px; /* 小透视值增强效果 */
}

.parallax-layer {
  position: absolute;
  width: 100%;
  height: 200%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 48px;
  font-weight: bold;
}

.background {
  background: linear-gradient(135deg, #667eea, #764ba2);
  transform: translateZ(-2px) scale(3);
  /* 后退2px,放大补偿,滚动时移动最慢 */
}

.middle {
  background: linear-gradient(
    135deg,
    rgba(46, 204, 113, 0.8),
    rgba(52, 152, 219, 0.8)
  );
  transform: translateZ(-1px) scale(2);
  /* 后退1px,适度放大 */
}

.foreground {
  background: linear-gradient(
    135deg,
    rgba(231, 76, 60, 0.9),
    rgba(243, 156, 18, 0.9)
  );
  transform: translateZ(0);
  /* 前景层,滚动最快 */
}

性能优化与最佳实践

使用 transform 而非 position

css
/* ❌ 低性能:触发重排 */
.box {
  position: relative;
  animation: move 1s infinite;
}

@keyframes move {
  to {
    left: 100px;
    top: 50px;
  }
}

/* ✅ 高性能:只触发合成 */
.box {
  animation: moveOptimized 1s infinite;
}

@keyframes moveOptimized {
  to {
    transform: translate(100px, 50px);
  }
}

使用 will-change

css
.heavy-transform {
  will-change: transform;
  transition: transform 0.5s;
}

.heavy-transform:hover {
  transform: rotate3d(1, 1, 1, 360deg) scale(1.5);
}

避免过度使用 3D

3D 变换比 2D 更消耗资源,只在必要时使用。

css
/* ✅ 简单场景用 2D */
.simple-hover {
  transition: transform 0.3s;
}

.simple-hover:hover {
  transform: translateY(-5px); /* 而不是 translateZ(5px) */
}

常见问题与解决方案

问题 1:3D 变换在移动端模糊

某些设备的 3D 渲染可能导致模糊。

css
/* 解决方案:添加抗锯齿 */
.element {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

问题 2:变换后元素超出父容器

变换不影响布局,可能导致溢出。

css
/* 解决方案:隐藏溢出或调整容器 */
.container {
  overflow: hidden;
}

/* 或者给容器留足够空间 */
.container {
  padding: 50px;
}

问题 3:Z 轴顺序问题

3D 空间中的元素可能遮挡关系混乱。

css
/* 使用 translateZ 微调 */
.top-element {
  transform: translateZ(1px); /* 稍微向前,确保在上层 */
}

问题 4:Safari 中 3D 效果闪烁

css
/* 解决方案:强制硬件加速 */
.element {
  -webkit-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);
}

总结

CSS Transform 是创造动态、引人注目视觉效果的强大工具:

2D 变换

  • translate:移动元素,性能最佳
  • rotate:旋转元素
  • scale:缩放元素
  • skew:倾斜元素

3D 变换

  • 需要设置 perspective 才能看到效果
  • 使用 transform-style: preserve-3d 保留 3D 空间
  • backface-visibility 控制背面可见性

最佳实践

  1. 性能优先:使用 transform 代替 position 或尺寸变化
  2. 组合顺序:通常 translate → rotate → scale
  3. 适度使用:过多 3D 变换影响性能
  4. 浏览器兼容:较老浏览器需要 -webkit- 前缀
  5. 配合过渡:与 transition 结合创造流畅动画

Transform 不仅仅是移动和旋转元素——它改变了我们思考网页空间的方式。从简单的悬停效果到复杂的 3D 场景,transform 让平面的网页获得了深度和动感。最好的变换效果是那些增强用户体验而不分散注意力的——它们应该服务于内容,而不是喧宾夺主。