文章目录
- [1. 永远要分清的两个"原点"](#1. 永远要分清的两个“原点”)
- [2. 2D 变换](#2. 2D 变换)
-
- [2.1 2D 位移](#2.1 2D 位移)
- [2.2 2D 缩放](#2.2 2D 缩放)
- [2.3 2D 旋转](#2.3 2D 旋转)
- [2.4 变换原点](#2.4 变换原点)
- [2.5 多重变换与坐标系的变化(核心原理)](#2.5 多重变换与坐标系的变化(核心原理))
- [3. 3D 变换](#3. 3D 变换)
-
- [3.1 3D 变换的准备工作](#3.1 3D 变换的准备工作)
-
- [3.1.1 开启 3D 空间 (transform-style)](#3.1.1 开启 3D 空间 (transform-style))
- [3.1.2 设置景深 (perspective)](#3.1.2 设置景深 (perspective))
- [3.1.3 透视点位置 (perspective-origin)](#3.1.3 透视点位置 (perspective-origin))
- [3.2 3D 位移](#3.2 3D 位移)
- [3.3 3D 缩放](#3.3 3D 缩放)
- [3.4 3D 旋转](#3.4 3D 旋转)
- [3.5 变换原点](#3.5 变换原点)
- [3.6 背部可见性](#3.6 背部可见性)
- [3.7 多重变换](#3.7 多重变换)
- [4. 常见疑问解答与总结](#4. 常见疑问解答与总结)
开启本小节学习之前,请大家带上富有想象力的立体思维~本小节的核心就是变形 transform。
1. 永远要分清的两个"原点"
在踏入 2D 和 3D 变换前,有一个极其重要的基础概念------坐标系原点 和变换中心点是两个完全不同的东西。
| 名称 | 是什么 | 默认位置 | 由什么决定 |
|---|---|---|---|
| 当前坐标系的坐标原点 | 测量所有坐标 (0,0) 的零点,位移的参考基准 | 元素的左上角 | 之前应用的变换(位移/旋转/缩放都会移动原点) |
| 旋转/缩放的中心点 | 元素绕哪个点旋转、从哪个点向外缩放 | 元素的几何中心(50% 50%) | transform-origin 属性 |
默认情况下,这两个点绝对不是同一个点:一个是左上角,一个是中心。
如下图所示二维平面:橙色代表元素盒子,蓝色坐标系是位移的参考系,绿色点是旋转和缩放的原点。

三维类似,多一个Z轴。

接下来的所有示例中,请时刻关注这两个"参考点",这是理解变换效果(尤其是复合变换)的绝对前提。
2. 2D 变换
2.1 2D 位移
给元素设置 transform 属性,再用以下函数指定位移:
| 函数 | 参数 | 含义 | 示例 |
|---|---|---|---|
translateX |
长度值(px、%等) | 仅水平位移 | translateX(50px) 右移50px;translateX(50%) 右移自身宽度的50% |
translateY |
长度值 | 仅垂直位移 | translateY(20px) 下移20px;translateY(-20%) 上移自身高度的20% |
translate |
1个值:水平 2个值:水平 垂直 | 复合位移;1个值只设水平(垂直为0) | translate(30px) 右移30px;translate(20px, 40px) 右移20px+下移40px |
百分比 :参考的是元素自身 的宽/高,而非父元素。
注意 :位移对行内元素 (如普通 <span>)无效。
示例:
css
transform: translate(150px,150px)

示例:
css
transform: translate(50%,50%) ;

对比:2D 位移 vs. 相对定位
| 2D 位移(translate) | 相对定位(position:relative + top/left) | |
|---|---|---|
| 是否脱离文档流 | ❌ 不脱离 | ❌ 不脱离 |
| 对其他元素布局的影响 | 无 | 无 |
| 百分比参照物 | 自身的宽/高 | 父元素的宽/高 |
| 能否作为定位包含块(子绝父相) | ❌ 不能 | ✅ 可以 |
| 典型用途 | 动画、元素自身居中 | 微调位置、创建"定位上下文" |
浏览器针对位移有优化,与定位相比,浏览器处理位移的效率更高。所以如果考虑是相同效果的场景下可以先考虑使用位移。
经典居中技巧 :让子元素先用定位 left:50%; top:50%;(移到父元素中心),再用 transform: translate(-50%, -50%);(回移自身的一半),即可精确居中。
css
.box {
position : absolute ;
left : 50%;
top : 50%;
transform : translate(-50%, -50%);
}
2.2 2D 缩放
| 函数 | 参数 | 含义 | 示例 |
|---|---|---|---|
scaleX |
数字 | 仅水平缩放,1为原大 | scaleX(1.5) 水平扩大到1.5倍 |
scaleY |
数字 | 仅垂直缩放 | scaleY(0.5) 垂直缩小一半 |
scale |
1个数字:宽高同时缩放 2个数字:水平 垂直 | 统一缩放或分别控制 | scale(0.5) 整体缩小一半;scale(2, 0.5) 水平拉长两倍、垂直压扁一半 |
注意translate只写一个值默认水平,scale只写一个值默认宽高同时缩放。
- 缩放只接受无单位数字,1 表示原大小,大于 1 放大,小于 1 缩小。
- 同样对行内元素无效。
- 缩放的值会影响坐标系的刻度,导致后续位移的距离也跟着缩放(后文详述)。
示例:
css
transform: scale(0.5) ;

技巧:如何实现比浏览器最小字号还小的文字?
浏览器最小字体通常为 12px,但你可以用 transform: scale(0.5) 将已设置 font-size: 12px 的元素缩小一半,视觉上变成 6px。
2.3 2D 旋转
| 函数 | 参数 | 含义 | 示例 |
|---|---|---|---|
rotate |
角度(deg) | 绕 Z 轴旋转;正值顺时针,负值逆时针 | rotate(45deg) 顺时针45°;rotate(-90deg) 逆时针90° |
注意 :
rotate()等同于rotateZ(),本质是绕Z轴(从屏幕射向你的那条轴)旋转,并非绕 X 轴。2D 平面就是 XY 平面,旋转轴垂直该平面即为 Z 轴。

2.4 变换原点
使用 transform-origin 可改变旋转或缩放的中心点。
- 该属性不影响位移的参考坐标系(位移始终基于坐标系原点移动)。所以变换原点对旋转和缩放有影响对位移没有影响。
- 取值参考的是元素自身的宽高。
取值规则详解 :
transform-origin 可以接受 1 个、2 个或 3 个值(3D 场景才用第三个 Z 轴值)。这里我们重点讲 1~2 个值的情况。
① 两个值:第一个是横坐标,第二个是纵坐标。
每个值都可以是长度值(像素等)、百分比、或方向关键字 (left``center``right``top``bottom)。
② 一个值:要分两种情况。
| 一个值的情况 | 另一个轴的默认值 | 示例 |
|---|---|---|
| 值是长度或百分比 | 纵坐标默认为 50%(即垂直居中) | transform-origin: 0; → 原点在 (0, 50%),左边缘中点 |
| 值是方向关键字(指代上下左右时) | 另一个轴取 50% | transform-origin: top; → 原点在 (50%, 0),上边缘中点 |
为了让规则更好记,更好理解,可以看下面这张速查表:
| 你的写法 | 实际等价于 | 原点到底在哪 |
|---|---|---|
0% 0% |
0% 0% |
左上角 |
0 0 |
0% 0% |
左上角 |
200px 100px |
200px 100px |
距左 200px,距上 100px |
right bottom |
100% 100% |
右下角 |
0 |
0% 50% |
左边缘,垂直居中 |
left |
0% 50% |
左边缘,垂直居中 |
top |
50% 0% |
上边缘,水平居中 |
100px |
100px 50% |
距左 100px,垂直居中 |
示例:
css
transform: rotate(30deg);
transform-origin: 0% 0%; /* 左上角 */

2.5 多重变换与坐标系的变化(核心原理)
当多个变换写在同一个 transform 中时,每步变换都可能会改变后续步骤的坐标系(原点位置、方向与刻度)。
想象你手里拿着一张透明塑料片(元素),上面印着图案。初始坐标系原点在塑料片左上角 ,旋转/缩放中心在塑料片中心。
- 位移:捏住左上角移动,原点跟着移动,中心点也一起平移(但相对塑料片的位置不变)。
- 旋转 :用针钉住中心点,转动塑料片,左上角(原点)绕中心画弧,坐标系方向改变。
- 缩放 :用针钉住中心点,拉伸或压缩塑料片,坐标系刻度被缩放,左上角(原点)也会移动。
核心结论:旋转和缩放以
transform-origin为中心,并会移动坐标系原点;位移则带着整个坐标系(包括中心点)一起走,不会改变旋转/缩放中心相对于塑料片的位置。
通过四个对比案例来彻底理解一下:
案例1:先平移,再缩放
css
transform: translate(150px, 150px) scale(0.5);
初始状态
- 坐标系原点:左上角 (0, 0)
- 旋转/缩放中心:几何中心 (150, 150)

第一步:平移 (150, 150)
平移移动的是整个坐标系,包括坐标原点和中心点。
- 坐标系原点从 (0, 0) → (150, 150)
- 中心点也同步平移:原 (150, 150) → (300, 300)

第二步:缩放 0.5 倍
缩放操作以当前中心点 (300, 300) 为基准,向该点收缩。
最终结果 :

案例2:先缩放,再平移
css
transform: scale(0.5) translate(150px, 150px);
初始状态
- 坐标系原点:(0, 0)
- 中心点:(150, 150)

第一步:缩放 0.5 倍
以中心点 (150, 150) 为基准收缩。
- 中心点不变:(150, 150)
- 坐标原点向中心点靠近:从 (0,0) 变为 (150 - 150×0.5, 150 - 150×0.5) = (75, 75)
- 坐标系刻度变为 1 单位 = 0.5px

第二步:平移 (150, 150)
注意这时是在已被缩放的坐标系 中移动。
平移 150 单位,实际屏幕移动距离 = 150 × 0.5 = 75px。
- 坐标系原点从 (75, 75) → (150, 150)
- 中心点同步平移:从 (150, 150) → (225, 225)
最终结果 :

对比案例1和案例2,最终位置完全不同,根本原因就在于平移发生的时刻不同,所使用的坐标系刻度不一样。
案例3:先平移,再旋转
css
transform: translate(150px, 150px) rotate(30deg);
初始状态
- 原点:(0,0),中心点:(150,150)

第一步:平移 (150, 150)
- 原点 → (150, 150),中心点 → (300, 300)

第二步:旋转 30°
旋转以当前中心点 (300, 300) 为轴进行。
- 中心点不动
- 坐标系原点绕中心点顺时针旋转 30°,位置发生弧线偏移
- 坐标系的方向也随之旋转 30°
最终结果 :

案例4:先旋转,再平移
css
transform: rotate(30deg) translate(150px, 150px);
初始状态
- 原点:(0,0),中心点:(150,150)

第一步:旋转 30°
以中心点 (150, 150) 为轴旋转。
- 中心点位置不变
- 坐标原点绕 (150, 150) 顺时针旋转 30°,移到了一个新位置
- 坐标系方向倾斜 30°

第二步:平移 (150, 150)
此时移动是沿已旋转坐标系的 X、Y 轴方向进行。
- 视觉上的位移方向不是纯水平/垂直,而是斜着移动
- 原点再沿新轴移动 150 单位,中心点也同步平移
最终结果

注意,这个最终状态下,当你用开发者工具查看旋转角度时,会发现元素好像围绕着一个原点旋转(150px,150px)为什么?因为你先设置的旋转,旋转开始的时候参考点就是(150px,150px),最后位移。这个最终结果是位移之后的,但是当时旋转参考的是初始状态。
实践建议:
- 尽量把
translate放在变换列表的最前面,这样位移参考系不受缩放和旋转影响,推理简单。
示例:
css
transform:translate(150px,150px) scale(0.5) rotate(30deg) ;

- 如果必须先旋转或缩放再移动,时刻记住坐标系已经被扭曲,移动的方向和距离都不再是屏幕像素上的直观数值。
这个参考系追踪的方法就是打通多重变换的最核心思维,所有 3D 复合变换也完全遵循同一套规则。
3. 3D 变换
3.1 3D 变换的准备工作
所有以下属性都要设置在父元素上!
在 2D 空间中,所有元素都是平面上的纸片。要让它们在三维空间中立起来、产生立体穿插,需要先搭建一个"3D 舞台"。这需要三步:开启 3D 空间 、设置景深 、(可选)调整透视点。
3.1.1 开启 3D 空间 (transform-style)
它是什么?
控制子元素是否位于三维空间中。默认情况下,即使子元素做了 3D 变换,它们也会被"拍扁"在父元素的 2D 平面上。
为什么需要它?
如果不开启,多个子元素即使设置了 translateZ 或 rotateY,看起来也还是像一张张摞在一起的纸片,无法实现真正的立体穿插效果。开启后可让子元素真正分布在 Z 轴不同深度。
怎么设置?
css
父元素 {
transform-style: preserve-3d; /* 开启 3D 空间 */
}
| 可选值 | 含义 |
|---|---|
flat |
默认值。子元素被强制压扁在父元素的 2D 平面内,无视 Z 轴层级。 |
preserve-3d |
子元素保留各自的三维变换,真正位于 Z 轴不同深度。 |
注意事项
- 必须设置在直接父元素上,中间层级中断则 3D 失效。
transform-style只影响子元素,不影响自身。
3.1.2 设置景深 (perspective)
它是什么?
景深(透视距离)是观察者(你)到 屏幕(z=0 平面) 的距离。可以想象成你离窗户有多远。
如图理解景深,白线为 z=0 平面,perspective 即为观察者到该平面的距离。

为什么需要它?
没有景深时,3D 旋转就像看一张纸片转动,无近大远小;设置了景深后,元素旋转时近的部分变大、远的部分变小,产生逼真的立体透视感。
如图所示,设置景深后,立体感明显增强:

怎么设置?
css
父元素 {
perspective: 600px; /* 推荐起始值 */
}
| 景深值 | 效果 | 类比 |
|---|---|---|
| 很小(如 100px) | 透视极度夸张,旋转时有"扑面而来"感 | 贴着窗户玻璃看 |
| 适中(600px~1200px) | 自然的立体透视 | 正常视角 |
| 很大(如 5000px) | 透视很弱,近乎平行投影 | 拿望远镜看 |
none(默认) |
无透视,完全等距投影 | --- |
注意事项
- 景深不宜太小,若小于元素尺寸的一半,旋转时元素会感觉"贴脸",失真。通常设置大于元素宽高的一半,再微调。
- 默认值为
none,不是 0 ,0 无意义,none就是没有透视。 - 景深加在父元素上,让所有子元素共享同一透视效果。
3.1.3 透视点位置 (perspective-origin)
它是什么?
透视点就是观察者的眼睛站在哪里看 。perspective-origin 设定了观察点在屏幕平面上的投影位置,相当于人站在哪个角度去看舞台。
为什么需要它?
默认观察点在父元素正中心,对于大多数居中交互是合适的。但有时你需要模拟人从侧面或上方往下看的效果,此时调整透视点即可改变立体感的偏向方向。
怎么设置?
css
父元素 {
perspective: 600px;
perspective-origin: 50% 50%; /* 默认值,中心点 */
}
属性的坐标系统与父元素的 XY 轴一致:
| 位置 | 示例 |
|---|---|
| 正中心(默认) | 50% 50% 或 center center |
| 从右侧看 | 100% 50% |
| 从上方看 | 50% 0% |
默认透视点在中心:

调整透视点,相当于人移动到不同位置观察,景深就是我们和平面的距离,xy透视点位置属性的坐标系统与父元素的 XY 轴 一致,所以说设定了观察点在屏幕平面上的投影位置。

注意事项
- 透视点必须与
perspective配合使用,单独设置无效。 - 通常情况下,无需修改,默认中心点就很好。
这三个属性构成了 3D 变换的"舞台":transform-style 搭建立体容器,perspective 制造近大远小,perspective-origin 决定从哪个角度观看。搭建好后,子元素就能自由地进行 3D 位移、旋转和缩放了。
3.2 3D 位移
在 2D 位移的基础上增加了 Z 轴。
| 函数 | 参数 | 含义 | 示例 |
|---|---|---|---|
translateZ |
长度值(❌不支持百分比) | 正值向屏幕外(靠近你),负值向屏幕里 | translateZ(50px) |
translate3d |
三个长度值:X, Y, Z(三个参数缺一不可) | 同时设置三维空间中的位移。不移动的轴写 0 | translate3d(10px, 20px, 30px) |
为什么不支持百分比? Z 轴位移沿视线方向,没有"自身高度"这样的参照物可计算百分比。
z位移如果超过景深,就无法看到物体
3.3 3D 缩放
| 函数 | 参数 | 含义 | 示例 |
|---|---|---|---|
scaleZ |
数字 | 沿 Z 轴缩放,影响后续旋转/透视时的厚度 | scaleZ(1.5) |
scale3d |
(x, y, z) 三个数字,缺一不可 | 三维缩放 | scale3d(1, 1, 1.5) 仅拉伸 Z 轴 |
虽然单纯缩放 Z 轴在静态画面中看不出厚度变化,但它改变了坐标系 Z 轴刻度。当元素后续绕 X/Y 轴旋转时,"厚度"变大,旋转出的立体感会更强。当你旋转一个薄的事物和一个厚的事物的时候是不一样的,厚的事物会更贴近我们。有的博主说影响景深我猜测也是这个道理。
对比如下(均有旋转45°):
- 无 scaleZ 额外拉伸:

- scaleZ(1.5):元素旋转后显得更"厚",更靠近观察者。

3.4 3D 旋转
在 2D 旋转的基础上增加了 沿x 轴和y 轴旋转。
| 函数 | 参数 | 含义 | 示例 |
|---|---|---|---|
rotateX |
角度(deg) | 绕 X 轴 旋转。 面向 X 轴正方向(即从屏幕右侧看): 正值,使元素顺时针旋转(向上方向外翻); 负值,使元素逆时针旋转 | rotateX(45deg) |
rotateY |
角度(deg) | 绕 Y 轴 旋转。 面向 Y 轴正方向(即从屏幕下方往上看):正值使元素顺时针旋转(右半部向屏幕内转); 负值,使元素逆时针旋转 | rotateY(60deg) |
rotate3d |
(x, y, z, 角度) 4 个参数,缺一不可 | 绕自定义方向向量旋转,前三个数字表示旋转轴方向(自动归一化) | rotate3d(1,1,1, 30deg) 沿对角线转 |
X 轴和 Y 轴的旋转轴都穿过元素的 transform-origin(默认中心),不是从屏幕边缘开始转。如图所示为绕x轴旋转的顺时针方向,重点展示理解正直旋转顺时针方向。

3.5 变换原点
transform-origin 在 3D 空间同样控制旋转与缩放的中心。
- 可以设置三个值:X 偏移、Y 偏移、Z 偏移(Z 偏移为长度值,如
transform-origin: 50px 50px 20px;)。 transform-origin只平移变换中心,不改变坐标轴方向。Z 偏移让旋转中心变远变近,元素像绕着更远(或更近)的枢轴转动,从而产生不同的翻转视觉效果。- 原点偏移方向 ≠ 旋转轴方向时,才能改变视觉上的变换效果
❌ 无效:Z轴偏移 + rotateZ
css
transform: rotateZ(45deg);
transform-origin: 0 0 -110px;

- 旋转轴是 Z,偏移也是 Z → 同方向,轴沿自身元素滑动,画面不变
✅ 有效:Z轴偏移 + rotateY
css
transform: rotateY(45deg);
transform-origin: 0 0 -110px;

- 旋转轴是Y,偏移是Z→ Z 偏移与 Y 轴垂直 → 旋转轴在屏幕深处 110px,元素像绕着背后的柱子翻转,视觉效果变换,3D 感极强。
核心结论
transform-origin的偏移只有在垂直于旋转轴 的方向上,才能改变视觉上的变换效果。偏移量平行于旋转轴时,只是轴在自身方向上的滑动,不会产生新的视觉变化。
与 2D 相同,transform-origin不影响位移的参考系。
3.6 背部可见性
backface-visibility 决定元素背面朝向观察者 时是否可见,加在变换元素自身上。
visible(默认):可见,会显示正面的镜像。hidden:隐藏,常用于翻转卡片效果,避免背面透出。
当元素绕 Y 轴转 180° 时,背面朝向屏幕,hidden 值可使其消失。

3.7 多重变换
3D 场景中的复合变换与 2D 原理完全一致:每步可能改变坐标系。实际开发中 3D 复合变换相对少见,更依赖单轴的精细控制,此处不再赘述。
4. 常见疑问解答与总结
Q1:为什么 transform 对行内元素无效?
CSS 规范规定,可变换元素 是指所有由盒模型控制布局的元素,但排除了非替换的行内框 (如 <span>、<a> 默认状态)、表格列、表格列组。因此行内元素无法变换,所有变换函数(位移、缩放、旋转)都一样。
解决办法 :设置 display: inline-block 或 block 即可。
Q2:什么时候用 translate,什么时候用 relative 定位?
- 动画/过渡:优先用
translate,因为它会交给 GPU 合成,性能更好,不触发重排。 - 纯粹微调位置但需要保留原本的包含块功能:使用相对定位。
- 居中定位:
translate配合百分比可基于自身尺寸精准居中,简单高效。
Q3:缩放会影响后续位移,到底怎么理解?
缩放会改变坐标系的刻度尺 。假设元素缩放 0.5 倍,坐标系上"1 个单位"就只对应屏幕上的 0.5px。如果在这之后再位移 100px,实际屏幕上的移动就只有 50px。这就是为什么位移放前面可以避免距离被缩放。
2D / 3D 变换速查总表
| 类型 | 2D 函数 | 3D 扩展函数 | 关键差异 |
|---|---|---|---|
| 位移 | translateX/Y translate |
translateZ translate3d |
3D 增加 Z 轴,不支持百分比;需父元素 设置3D 变换前提属性 |
| 缩放 | scaleX/Y scale |
scaleZ scale3d |
3D 增加 Z 轴厚度,影响旋转后的视觉厚度;需父元素 设置3D 变换前提属性 |
| 旋转 | rotate (绕Z轴) |
rotateX/Y rotate3d |
3D 可绕 X/Y 轴或任意轴翻转,需透视才能看到效果;需父元素 设置3D 变换前提属性 |
| 中心点 | transform-origin |
transform-origin (可设Z偏移) |
3D 支持 Z 方向调整旋转轴位置;需父元素 设置3D 变换前提属性 |
小结:理解两个原点(坐标系原点 vs 变换中心点)和坐标系动态变化,是彻底掌握 CSS Transform 的钥匙。2D 与 3D 变换本质上共享同一套规则,只是 3D 多了一个维度、需要父元素开启景深与 3D 空间。
以上为个人学习总结,旨在梳理个人理解。如有疏漏或不当之处,欢迎指正与交流。
