通过单独的变换属性更精细地控制 CSS 变换

使用 translaterotatescale 属性变换元素

CSS transform 属性

要将变换应用于元素,请使用 CSS transform 属性。该属性接受一个或多个 <transform-function>,它们会依次应用。

.target {
  transform: translateX(50%) rotate(30deg) scale(1.2);
}

目标元素在 X 轴上平移 50%,旋转 30 度,最后缩放到 120%。

虽然 transform 属性可以很好地完成其工作,但当您想要单独更改其中任何一个值时,它会变得有点乏味。

要在悬停时更改比例,您必须复制 transform 属性中的所有函数,即使它们的值保持不变。

.target:hover {
  transform: translateX(50%) rotate(30deg) scale(2); /* Only the value of scale() changed */
}

单独的变换属性

Chrome 104 中引入了 CSS 变换的单独属性。这些属性是 scalerotatetranslate,您可以使用它们来单独定义变换的这些部分。

通过这样做,Chrome 加入了已经支持这些属性的 Firefox 和 Safari。

浏览器支持

  • Chrome: 104.
  • Edge: 104.
  • Firefox: 72.
  • Safari: 14.1.

来源

使用单独属性重写前面的 transform 示例,您的代码段将变为这样

.target {
  translate: 50% 0;
  rotate: 30deg;
  scale: 1.2;
}

顺序很重要

原始 CSS transform 属性与新属性之间的一个关键区别是声明的变换的应用顺序。

对于 transform,变换函数按照它们编写的顺序应用 – 从左(外部)到右(内部)。

对于单独的变换属性,顺序不是它们声明的顺序。顺序始终相同:先 translate(外部),然后 rotate,最后 scale(内部)。

这意味着以下两个代码段都给出相同的结果

.transform--individual {
  translate: 50% 0;
  rotate: 30deg;
  scale: 1.2;
}

.transform--individual-alt {
  rotate: 30deg;
  translate: 50% 0;
  scale: 1.2;
}

在这两种情况下,目标元素都将首先在 X 轴上平移 50%,然后旋转 30deg,最后缩放 1.2

如果单独的变换属性之一与 transform 属性一起声明,则单独的变换首先应用(translaterotate,然后是 scale),而 transform 最后应用(内部)。有关更多详细信息,请参阅定义 如何计算变换矩阵 的规范。

动画

添加这些属性的主要原因是为了使动画更轻松。假设您想要按如下方式为元素设置动画

Keyframes graph.

使用 transform

要使用 transform 实现此动画,您必须计算所有已定义变换的所有中间值,并将这些值包含在每个关键帧中。例如,要在 10% 标记处进行旋转,还必须计算其他变换的值,因为 transform 属性需要所有这些值。

Keyframes graph with intermediate values calculated.

生成的 CSS 代码变为这样

@keyframes anim {
  0% { transform: translateX(0%); }
  5% { transform: translateX(5%) rotate(90deg) scale(1.2); }
  10% { transform: translateX(10%) rotate(180deg) scale(1.2); }
  90% { transform: translateX(90%) rotate(180deg) scale(1.2); }
  95% { transform: translateX(95%) rotate(270deg) scale(1.2); }
  100% { transform: translateX(100%) rotate(360deg); }
}

.target {
  animation: anim 2s;
  animation-fill-mode: forwards;
}

使用单独的变换属性

使用单独的变换属性,这变得更容易编写。您无需将所有变换从一个关键帧拖动到另一个关键帧,而是可以单独定位每个变换。您也不再需要计算所有这些中间值。

@keyframes anim {
  0% { translate: 0% 0; }
  100% { translate: 100% 0; }

  0%, 100% { scale: 1; }
  5%, 95% { scale: 1.2; }

  0% { rotate: 0deg; }
  10%, 90% { rotate: 180deg; }
  100% { rotate: 360deg; }
}

.target {
  animation: anim 2s;
  animation-fill-mode: forwards;
}

使用单独的变换属性和多个关键帧

为了使您的代码模块化,您可以将每个子动画拆分为其自己的一组关键帧。

@keyframes move {
  0% { translate: 0% 0; }
  100% { translate: 100% 0; }
}

@keyframes scale {
  0%, 100% { scale: 1; }
  5%, 95% { scale: 1.2; }
}

@keyframes rotate {
  0% { rotate: 0deg; }
  10%, 90% { rotate: 180deg; }
  100% { rotate: 360deg; }
}

.target {
  animation: move 2s, scale 2s, rotate 2s;
  animation-fill-mode: forwards;
}

由于这种拆分,您可以根据需要应用每个单独的关键帧集,因为 transform 属性(现在已成为单独的属性)不再相互覆盖。最重要的是,您可以为每个变换赋予不同的时序,而无需重写全部内容。

性能

使用这些新属性的动画与现有 transform 属性的动画一样高效。

translaterotatescale 的动画在合成器上以与 transform 动画相同的方式运行,因此它们在 transform 相同的方式 中有利于动画性能。

这些新属性也适用于 will-change 属性。通常,最好避免过度使用 will-change,方法是在所需的最少数量的元素上使用它,并在尽可能短的时间内使用它。但尽可能具体也是有益的。例如,如果您使用 will-change 来优化具有 rotatefilter 属性的动画,则应使用 will-change: rotate, filter 声明此内容。在您为 rotatefilter 设置动画的情况下,这比使用 will-change: transform, filter 稍好,因为当您使用 will-change 时,Chrome 预先创建的一些数据结构对于 transformrotate 是不同的。

新近可互操作系列”的一部分