3. 2D变换与3D变换:熟练使用transform进行平移、旋转、缩放、倾斜,理解3D空间与透视原理
说到CSS的transform,我脑子里第一个蹦出来的词就是「魔法」。你想想看,一个静态的div,加上几行代码,就能在屏幕上飞来飞去、旋转跳跃,这感觉确实挺爽的。
但说实话,我刚入行那会儿,对transform的理解也就停留在「能转能移」的层面。直到有一次做H5活动页,需要做一个3D翻转的卡片效果,我才发现——嗯,这东西远比我以为的深。
3.1 2D变换:四个基本功
2D变换说白了就四种操作:平移、旋转、缩放、倾斜。咱们一个一个来。
3.1.1 平移(translate)
平移是最直观的。让元素在X轴或Y轴上移动,就这么简单。
/* 向右移动50px,向下移动100px */
.element {
transform: translate(50px, 100px);
}
/* 只移动X轴 */
.element-x {
transform: translateX(50px);
}
/* 只移动Y轴 */
.element-y {
transform: translateY(100px);
}
我个人习惯用百分比来做居中,比如:
.center-box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
这个技巧我用了快十年了,百试百灵。它比margin负值好使,因为不用知道元素本身的宽高。
3.1.2 旋转(rotate)
旋转的单位是deg(度)。一圈是360deg。
.rotate-45 {
transform: rotate(45deg);
}
.rotate-half {
transform: rotate(180deg);
}
3.1.3 缩放(scale)
缩放的值是倍数。1是原大小,2是两倍,0.5是一半。
.scale-up {
transform: scale(1.5); /* 放大1.5倍 */
}
.scale-down {
transform: scale(0.8); /* 缩小到80% */
}
/* 单独控制X轴和Y轴 */
.scale-xy {
transform: scale(1.2, 0.8); /* 宽放大,高缩小 */
}
我曾经在项目中遇到过一个问题:用scale做hover放大效果时,旁边的元素会被挤开。后来发现,用scale其实不会改变元素的布局尺寸,只是视觉上变了。但如果你用了transform: scale,记得加上will-change来优化性能。
3.1.4 倾斜(skew)
倾斜这个操作,说实话用得不多。但做平行四边形按钮或者一些特殊字体效果时,它很管用。
.skew-x {
transform: skewX(10deg); /* X轴倾斜10度 */
}
.skew-y {
transform: skewY(10deg); /* Y轴倾斜10度 */
}
.skew-both {
transform: skew(10deg, 5deg); /* 两个方向一起 */
}
3.2 组合变换:顺序很重要
多个变换可以写在一起,但顺序会影响结果。为什么?因为CSS的变换是从右往左执行的。
/* 先平移,再旋转 */
.a {
transform: translate(100px, 0) rotate(45deg);
}
/* 先旋转,再平移 */
.b {
transform: rotate(45deg) translate(100px, 0);
}
这两个结果完全不一样。第一个是向右平移100px,然后原地旋转。第二个是先旋转45度,然后沿着旋转后的方向平移。说白了,坐标系变了。
我记得有次做loading动画,死活调不对位置,最后发现就是顺序写反了。从那以后,我每次写组合变换都会在脑子里过一遍执行顺序。
3.3 3D变换:进入立体世界
2D玩熟了,就该上3D了。3D变换比2D多了个Z轴,也就是深度。
3.3.1 开启3D空间
想让元素在3D空间里变换,得先告诉浏览器:「我要用3D了」。这个开关就是perspective。
.scene {
perspective: 800px; /* 视距,相当于眼睛到屏幕的距离 */
}
.card {
transform: rotateY(45deg);
}
perspective可以加在父元素上,也可以直接加在子元素上。我个人建议加在父元素上,这样所有子元素共享同一个3D空间,效果更统一。
3.3.2 3D平移、旋转、缩放
3D的平移多了个Z轴:
.move-3d {
transform: translate3d(50px, 100px, 200px);
/* X轴50px,Y轴100px,Z轴200px(朝你飞来) */
}
3D旋转也多了两个方向:
.rotate-x {
transform: rotateX(45deg); /* 绕X轴转,像翻书 */
}
.rotate-y {
transform: rotateY(45deg); /* 绕Y轴转,像转门 */
}
.rotate-z {
transform: rotateZ(45deg); /* 绕Z轴转,和2D的rotate一样 */
}
3D缩放同样可以控制Z轴:
.scale-3d {
transform: scale3d(1.5, 1.5, 2);
/* Z轴放大2倍,会让元素看起来更「厚」 */
}
3.3.3 透视原理:为什么近大远小?
你想想看,为什么3D变换能产生立体感?说白了就是透视。perspective的值越小,透视效果越强,变形越夸张。值越大,效果越平缓。
| perspective值 | 效果 | 适用场景 |
|---|---|---|
| 200px - 400px | 强烈透视,变形明显 | 特写、强调效果 |
| 600px - 1000px | 适中透视,自然立体 | 卡片翻转、3D轮播 |
| 1200px以上 | 弱透视,接近平面 | 大场景、远距离视角 |
3.4 实战:3D翻转卡片
说了这么多,来写个实际例子。3D翻转卡片是面试常考题,也是我当年第一个3D项目。
<div class="scene">
<div class="card">
<div class="front">正面</div>
<div class="back">背面</div>
</div>
</div>
<style>
.scene {
width: 200px;
height: 300px;
perspective: 800px;
}
.card {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s;
}
.card:hover {
transform: rotateY(180deg);
}
.front, .back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
}
.front {
background: #4A90D9;
}
.back {
background: #E74C3C;
transform: rotateY(180deg);
}
</style>
这里有几个关键点:
- transform-style: preserve-3d:让子元素在3D空间里保持位置关系。不加的话,子元素会被压平。
- backface-visibility: hidden:翻转时隐藏背面。不然你会看到卡片的「反面」。
- 两个面都要设position: absolute:让它们叠在一起。
3.5 性能优化:别让动画卡成PPT
3D变换比2D更耗性能。为什么?因为浏览器要计算深度、透视、遮挡关系。我总结了几条经验:
- 用transform代替left/top:transform不会触发重排,性能更好。
- 加will-change:告诉浏览器这个元素要变了,让它提前准备。
- 别滥用3D:不是所有动画都需要3D。2D能搞定的,就别上3D。
.optimized-card {
will-change: transform;
/* 或者更具体:will-change: transform, opacity; */
}
好了,2D和3D变换的核心内容就这些。说白了,2D是基础,3D是进阶。先把2D的平移旋转缩放练熟,再上手3D,你会发现——嗯,其实也没那么难。
下一章我们聊聊过渡和动画,看看怎么让这些变换动起来。到时候我会分享一个我做过的翻页动画案例,踩过的坑可不少。