Menu

CSS transform:translate、scale、skew 与 transform-origin

transform 属性可以移动、缩放、旋转和倾斜元素,而不改变周围的布局。本文讲解每个 transform 函数、函数顺序为什么重要、transform-origin、独立的 translate、scale 和 rotate 属性,以及用 translate(-50%, -50%) 居中的技巧。

本页包含可运行的编辑器。编辑、运行,立即查看输出。

transform 的作用

transform 改变元素的绘制方式:移动、缩放、旋转或倾斜。下面的虚线框标出了每个方块在没有 transform 时所在的位置:

translate(20px, 10px) 把蓝色方块向右移动 20px、向下移动 10px。scale(1.3) 让绿色方块以中心为基准放大 30%。rotate(20deg) 把琥珀色方块顺时针旋转,skewX(-20deg) 让深色方块倾斜。无论哪种情况,虚线框(也就是元素在布局中占据的空间)都完全留在原处。

transform 函数

函数作用示例
translate(x, y)移动translate(20px, -10px), translate(-50%, -50%)
translateX(x) / translateY(y)沿一个轴移动translateY(-4px)
scale(s) / scale(x, y)缩放(1 = 原始大小,0.5 = 一半,负值为镜像)scale(1.1), scale(-1, 1)
scaleX(s) / scaleY(s)沿一个轴缩放scaleX(0.5)
rotate(angle)顺时针旋转(负值为逆时针)rotate(45deg), rotate(0.25turn)
skew(x, y) / skewX(a) / skewY(a)倾斜skewX(-15deg)
matrix(a, b, c, d, e, f)用一个矩阵表示以上所有变换,多半是浏览器返回给你的形式
none不做变换

translate() 中的百分比相对于元素自身的尺寸,而不是父元素的尺寸。旋转有单独的一页,讲角度、圈数和旋转动画:CSS rotate。

transform 演练场

拖动滑块。第一行是你组合出的 transform 值;第二行是浏览器根据它计算出的矩阵,任何 transform 用 getComputedStyle 读取时返回的都是这个矩阵:

transform 不会移动布局

被变换的元素绘制在别的位置,但页面的布局就像它没有被变换一样。它的相邻元素保持原位。这正是 transform 适合做悬停效果和动画的原因:周围的东西都不会重新排版。

中间的两个方块看起来都大了 1.5 倍。被缩放的那个盖住了相邻元素,C 保持不动;用 width 和 height 放大的那个则把 C 往后推了 40px。

多个 transform 及其顺序

把多个函数写在同一个 transform 里,用空格分隔。顺序会改变结果,因为从左往右读,每个函数都在前面函数留下的坐标系中工作:

蓝色方块先直线移动了 120px,然后在原地旋转。绿色方块先旋转,所以它的“x 轴”指向斜下方,translateX(120px) 让它沿对角线向下移动。同样的函数,不同的位置。

另一个陷阱:第二条 transform 声明会替换第一条。如果卡片有 transform: rotate(-2deg),而它的悬停规则写的是 transform: scale(1.05),悬停时旋转就消失了。要么把两个都写上(rotate(-2deg) scale(1.05)),要么使用下面介绍的独立属性。

transform-origin

缩放、旋转和倾斜都围绕一个固定点进行,这个点就是变换原点,默认是中心。可以用关键字、长度或百分比修改它:

三个方块都旋转了 25 度。第一个绕中心旋转,第二个的左上角固定在虚线框的角上,第三个固定的是右下角。从按钮里展开的下拉菜单,就是用 transform-origin: top 配合 scale() 实现的。

translate、scale 和 rotate 属性

现代浏览器还提供了三个独立的属性,作用与对应的函数相同,但可以分别设置、分别做动画:

.card {
  rotate: -2deg;
  transition: scale 0.2s ease-out;
}
.card:hover {
  scale: 1.05;   /* the rotation stays, because it is a different property */
}

无论你按什么顺序声明,它们总是按 transform: translate(...) rotate(...) scale(...) 的顺序组合,并排在任何 transform 值之前。注意语法:translate: 10px 20px 和 scale: 1.2 的值不带函数括号。

用 translate(-50%, -50%) 居中

因为 translate() 的百分比相对于元素自身的尺寸,top: 50%; left: 50%; transform: translate(-50%, -50%) 可以让任意尺寸的绝对定位元素在父元素中居中。div 居中页面把它和 flexbox、grid 做了对比。

常见错误

  • 写了两条 transform 声明。后一条会完全覆盖前一条。把函数合并到一起,或者使用 rotate、scale 和 translate 属性。
  • 对行内元素做变换。普通的 <span> 或 <a> 会忽略 transform。把它设为 inline-block。
  • 以为相邻元素会跟着移动。transform 从不改变布局。要腾出空间,应修改 width、margin 或 gap。
  • 函数顺序写错。rotate() 写在 translate() 前面,会沿旋转后的轴移动。
  • position: fixed 子元素出现意外。被变换的元素会成为固定定位后代元素的包含块,所以放在里面的固定头部会跟着它滚动。它还会为 z-index 创建新的层叠上下文。

常见问题

CSS 中的 transform 是做什么的?

它改变元素的绘制方式:移动(translate)、缩放(scale)、旋转(rotate)或倾斜(skew)。元素在布局中仍占着原来的位置,所以周围的元素不会移动。

如何在 CSS 中同时应用多个 transform?

把它们写在同一个 transform 值里,用空格分隔:transform: translateX(50px) rotate(20deg) scale(1.2);。再写一条 transform 声明会替换第一条,而不是叠加上去。

transform 函数的顺序重要吗?

重要。从左往右读,每个函数都在前面函数留下的坐标轴上工作,所以 rotate(45deg) translateX(100px) 会沿旋转后的轴移动元素,而 translateX(100px) rotate(45deg) 先把它直线移动,再旋转。

transform-origin 是什么?

缩放、旋转和倾斜所围绕的固定点。默认是中心(50% 50%)。transform-origin: top left 让元素从左上角开始放大,或绕左上角旋转。

为什么 transform 对我的 span 不起作用?

transform 不作用于非替换的行内元素,比如普通的 <span> 或 <a>。给元素设置 display: inline-block 或 block,transform 就会生效。

Coddy 编程语言插图

和 Coddy 一起学编程

开始