先记住这个答案
transform 属性里可以写多个函数,比如 transform: rotate(45deg) translateX(100px)。浏览器从左到右依次执行这些函数,每个函数都会改变元素的本地坐标系。先 rotate(45deg) 会让坐标系旋转 45 度,然后 translateX(100px) 就是沿着旋转后的 X 轴方向移动,元素最终会向右下方移动。如果把顺序反过来写成 translateX(100px) rotate(45deg),元素先水平右移 100px,再在那个位置原地旋转 45 度,落点完全不同。
- 函数从左到右依次作用,每个都改变后续函数的坐标系
- 先旋转再位移,会沿旋转轴移动
- 调换变换函数顺序会改变最终位置
scale的位置会影响位移效果
一个对比实验看清区别
想象一个蓝色方块放在页面左上角,坐标原点在元素中心。
/* 先旋转再平移:沿 45 度方向飞出去 */
.box-a {
transform: rotate(45deg) translateX(100px);
}
/* 先平移再旋转:水平移动后原地转 */
.box-b {
transform: translateX(100px) rotate(45deg);
}.box-a 先把坐标系转了 45 度,这时候 X 轴指向右下方,再沿 X 轴走 100px,元素就到了右下方。.box-b 先沿水平方向走 100px,到了右边,然后在那个位置绕中心转 45 度,元素还是在正右边,只是歪了。
记忆口诀:左边的函数先改坐标系,右边的函数在改过的坐标系里执行。
scale 对位移距离的影响
scale 会缩放坐标系的单位长度。如果 scale(2) 写在 translateX(50px) 前面,坐标系的 1px 变成了 2px,实际移动距离就变成 100px。
反过来,translateX(50px) 写在前面,先移动 50px(坐标系还没缩放),再 scale(2) 让元素放大两倍,移动距离不受影响。
这是最容易踩坑的地方。布局时发现元素位置偏了,往往就是 scale 放在了 translate 前面。
独立变换属性的固定顺序
CSS 新增了 translate、rotate、scale 三个独立属性,可以分开写。它们的执行顺序是规范固定的:先 translate,再 rotate,最后 scale,和你在样式表里的书写顺序无关。
这意味着 translate: 100px 0; rotate: 45deg; 和 rotate: 45deg; translate: 100px 0; 的效果一模一样,都是先平移再旋转。如果你需要先旋转再平移的效果,就只能用 transform 属性把它们写在一个值里。
容易答错的地方
- 以为矩阵从右往左执行就意味着「右边的先算」
- 数学上确实是右乘,但理解方式应该是「从左到右依次作用在坐标系上」。面试时用坐标系的思路解释更清楚:左边的函数先改坐标系,右边的函数在改过的坐标系里操作。
- 把独立属性和 transform 属性的顺序规则搞混
transform: rotate() translate()的顺序你自己定。rotate: 45deg; translate: 100px;的顺序是规范定死的(translate 先执行)。混用时两者会叠加,独立属性先于transform执行。
面试官还会怎么问?
transform-origin 会影响函数的执行顺序吗?
不会影响执行顺序,但会影响旋转和缩放的参考点。默认是元素中心,改成 top left 后 rotate 就绕左上角转。执行顺序仍然是从左到右,只是每个函数的参考点变了。
怎么在动画里分别控制平移和旋转的时长?
用独立属性。translate 和 rotate 是两个属性,可以各自设不同的 transition-duration。用 transform 属性的话整个值是一体的,没法分开设时长。
多个 transform 声明会合并还是覆盖?
和其他 CSS 属性一样,后声明的覆盖前声明的。transform: rotate(45deg); 后面再写 transform: scale(2);,最终只有 scale(2) 生效,rotate 被覆盖了。想同时生效必须写在一个声明里:transform: rotate(45deg) scale(2);。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。