先记住这个答案
传统写法是把 rotate()、scale()、translate() 写在 transform 属性里,多个函数从左到右依次执行。CSS 新规范新增了 rotate、scale、translate 三个独立属性,它们的执行顺序是固定的(先 translate,再 rotate,最后 scale),和声明顺序无关。独立属性可以分别设过渡,做动画时控制粒度更细。两套写法可以同时存在,最终变换是叠加的。
- 独立变换按移动、旋转、缩放顺序应用
transform函数按书写顺序从左到右执行- 独立属性和
transform可以同时存在,不互相覆盖 - 独立属性能分别设
transition,做动画时更方便
transform 函数顺序的陷阱
transform 里面的函数从左到右依次执行,每一步都在前一步变换后的坐标系上操作。先平移再旋转,和先旋转再平移,结果完全不同。
/* 先平移再旋转:先右移 100px,再在新位置旋转 */
.box-a {
transform: translateX(100px) rotate(45deg);
}
/* 先旋转再平移:先旋转 45 度,X 轴方向变了,平移方向也变了 */
.box-b {
transform: rotate(45deg) translateX(100px);
}.box-a 先移到右边 100px 的位置,再原地转 45 度。.box-b 先转 45 度,这时 X 轴也跟着转了,再沿新的 X 轴方向移动 100px,最终位置偏向右下方。
写 transform 时必须想清楚顺序,否则结果和预期对不上。
独立属性的固定顺序
独立属性不需要纠结顺序。不管你在 CSS 里先写 rotate 还是先写 translate,浏览器始终按 translate -> rotate -> scale 的顺序执行。
.card {
translate: 100px 0; /* 先平移 */
rotate: 45deg; /* 再旋转 */
scale: 1.2; /* 最后缩放 */
/* 等同于 transform: translate(100px, 0) rotate(45deg) scale(1.2) */
}这个固定顺序在绝大多数场景下都是合理的:先把元素移到目标位置,再旋转,最后缩放。
独立属性做动画更灵活
用 transform 时,transition: transform 0.3s ease 会让所有变换函数一起过渡,没法给平移和旋转设不同的时长。独立属性就能分开控制。
.icon {
translate: 0 0;
rotate: 0deg;
transition: translate 0.2s ease-out, rotate 0.5s ease-in-out;
}
.icon:hover {
translate: 20px 0; /* 快速平移 */
rotate: 360deg; /* 慢慢旋转一圈 */
}平移在 0.2 秒内完成,旋转用 0.5 秒,两个动画各走各的节奏。用 transform 做不到这个效果,除非拆成两层 DOM 或者用 @keyframes 手动控制每一帧。
两套写法同时存在时的叠加规则
如果一个元素同时写了 transform 和独立属性,最终的变换矩阵是两者叠加的,不是互相覆盖。执行顺序是:先独立属性(translate -> rotate -> scale),再 transform。
这意味着你可以用独立属性做基础定位,用 transform 叠加额外效果,两者互不干扰。
容易答错的地方
- 以为独立属性会覆盖
transform - 两套写法是叠加关系。写了
translate: 100px 0又写了transform: translateX(50px),元素最终会平移 150px,不是只走 50px。 - 以为独立属性的执行顺序跟声明顺序有关
- 不管 CSS 里先写
scale还是先写translate,执行顺序始终是translate->rotate->scale。这和transform函数「从左到右」的规则不同。
面试官还会怎么问?
独立属性的浏览器兼容性怎么样?
Chrome 104、Firefox 72、Safari 14.1 开始支持。IE 完全不支持。如果项目需要兼容更老的浏览器,还是用 transform。可以用 @supports (translate: 0) 做渐进增强。
什么时候应该用独立属性代替 transform?
需要给不同变换设不同过渡时长时,或者想在 JavaScript 里单独修改某个变换(比如只改 rotate 不影响 translate)时,独立属性更方便。如果只是简单的一次性变换,transform 写在一行里更紧凑。
transform 里的函数顺序为什么那么重要?
因为每个函数都在前一个函数变换后的坐标系上操作。旋转 90 度之后,X 轴变成了原来的 Y 轴方向,后面的 translateX 就会沿原来的 Y 方向移动。理解这一点的关键是把每一步都想成「在当前坐标系里操作」。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。