Transform 实验室

CSS Transform 详解:从 2D 平移到 3D 透视的视觉魔法

2024-12-15 wangjun 15 min read
T()

为什么 Transform 如此特殊?

CSS transform 是少数能触发 GPU 合成层的属性之一。与 top/left 等触发重排的属性不同,transform 直接在合成阶段操作,不触发布局重计算,因此动画极其流畅。

2D 变换矩阵

所有 2D transform 最终都会被编译为一个 3×3 的仿射变换矩阵:

┌ a  c  e ┐
│ b  d  f │
└ 0  0  1 ┘

其中 translate(tx, ty) 对应 e=tx, f=tyscale(sx, sy) 对应 a=sx, d=sy,而 rotate(θ) 对应:

a = cos(θ)   c = -sin(θ)
b = sin(θ)   d = cos(θ)

变换原点 transform-origin

默认变换原点是元素中心 50% 50%。旋转和缩放都围绕这个点进行。修改 transform-origin 本质上是在变换前后各加一次平移:

M' = T(ox, oy) × M × T(-ox, -oy)

3D 变换与透视

3D 变换使用 4×4 矩阵。关键在于 perspective 属性 -- 它定义了观察者到 z=0 平面的距离,决定了 3D 透视的强度。

.card {
  perspective: 1000px;
}
.card-inner {
  transform: rotateY(60deg);
  transform-style: preserve-3d;
}

perspective 的数学原理

透视投影将 3D 坐标 (x, y, z) 映射到 2D 屏幕:

x' = x × d / (d - z)
y' = y × d / (d - z)

其中 d 是透视距离。z 越大(越靠近观察者),放大的比例越大。

实践:卡片翻转动画

.flip-card {
  perspective: 1000px;
}
.flip-inner {
  transform-style: preserve-3d;
  transition: transform 0.6s;
}
.flip-card:hover .flip-inner {
  transform: rotateY(180deg);
}
.flip-front, .flip-back {
  backface-visibility: hidden;
  position: absolute;
}
.flip-back {
  transform: rotateY(180deg);
}

性能最佳实践

  • 优先使用 transform 和 opacity:它们不触发布局和绘制,直接在合成层处理
  • will-change 提示:为即将动画的元素添加 will-change: transform
  • 避免嵌套 3D 上下文:过多的 preserve-3d 会导致性能下降
  • 使用 translate3d 强制 GPU 加速transform: translate3d(0,0,0)
Transform 的本质是矩阵乘法,而矩阵乘法的本质是线性变换的复合。理解了这一点,所有 CSS transform 的行为都有了数学解释。