11.7 CSS 变换(transform)

CSS3几何变换功能

我们已经熟悉如何用CSS控制字体、位置、间距等“几何”属性,而前面的章节我们了解到还可以使用CSS转换(transition)或动画(animation)来简单的改变这些“几何”属性。

CSS变换(transforms)就是一系列用来增强控制元素“几何”属性的方法,通过CSS transforms,元素将具备强大的几何变换(甚至3D变换)功能:

  • translate: 位移方法,包含3D版本,支持在3个坐标轴方向移动元素位置(x,y,z)
  • rotate: 旋转方法,使元素沿中心点旋转特定角度
  • scale: 伸缩方法,使元素放大或缩小
  • skew: 扭曲方法,使元素产生扭曲变形

transform 属性

有3个CSS transform 属性可用:

  • transform 定义使用哪个transform 方法(translate, rotate, scale…)
  • transform-origin 定义变换的原点(origin point),默认值为元素边框的中心点位置(以百分比定义:50% 50%),类似于前述的背景位置
  • transform-style 变换样式,取值为flat(平面)或preserve-3d(立体)。默认为flat。

backgroundborder 不同,transform 并不是一个速写属性。

不破坏文档流

为了避免意外行为,元素变换不该影响正常文档流,不管是旋转、缩放还是位移,都不会影响到其他元素。下面对这些变换方法逐一讲解。

位移(translate)

translate() 方法对应于平面几何(二维坐标系)的位移函数。 允许在x,y方向上移动元素。该方法的参数可以是:

  • 1个参数: 只在x坐标轴方向移动
  • 2个参数: 第一个参数代表x坐标轴位移,第二个参数代表y坐标轴位移。

位移功能的效果跟相对定位中通过 lefttop 来移动元素位置类似。

在前面的例子环游动画中,我们通过在@keyframe中改变left和top属性来移动元素,我们同样可以通过位移方法来达到同样的效果:

@keyframes translating {
  0%  { transform: translate(0, 0);}
  25% { transform: translate(240px, 0);}
  50% { transform: translate(240px, 240px);}
  75% { transform: translate(0, 240px);}
  100%{ transform: translate(0, 0);}
}
p{ animation: translating 4s linear infinite;}

Hello

transformleft一样是一个 CSS 属性(property),只不过这个属性的值(value)有点特殊,是一个函数translate()

使用translate()方法在动画语义上要比相对定义要明确。我们还可以使用 translateX()translateY() 来分别在x或y轴方向上平移。

旋转(rotate)

rotate() 函数允许元素绕着一个固定点(缺省情况下是该元素的中心点)进行旋转。好比转盘上的唱片。

rotate() 只有一个参数,单位可以是角度 (deg)、弧度 (grad)转数(turn) (1 turn = 360°)。

@keyframes rotating {
  0%  { transform: rotate(0deg);}
  100%{ transform: rotate(360deg);}
}
p{ animation: rotating 4s linear infinite;}

我的唱片

伸缩(scale)

scale() 函数允许调整元素的大小。该方法的参数可以是:

  • 1个参数: 按元素宽高的固定比例来调整大小
  • 2个参数: 第一个参数调整水平方向的大小,第二个为垂直方向。

可能的取值有:

  • 1: 保持原有大小
  • 2: 放大到2倍
  • 0.5: 缩小到1/2
  • 0: 零宽高,元素将不可见
  • -1: 将呈现元素的镜像
@keyframes scaling {
  0%  { transform: scale(1);}
  20%{ transform: scale(2);}
  40%{ transform: scale(0.5);}
  60%{ transform: scale(0);}
  80%{ transform: scale(-1);}
  100%{ transform: scale(1);}
}
p{ animation: scaling 10s steps(1) 0s infinite;}

scale(1): 原始大小

scale(2): 2倍

scale(0.5): 1/2

scale(0): 零宽高(不可见)

scale(-1): 显示镜像

Scaling

translate() 一样,scale() 方法也有后缀x和y版本:scaleX()scaleY(),分别调整水平和垂直方向的大小。

扭曲(skew)

skew() 函数允许扭曲一个元素,基本上是通过沿着一条轴线拉伸元素边缘来使其变形。

这个方法在几何变换上是有意义的,但是其实际视觉效果难以预料。踏得网首页中的标签云使用了轻度的扭曲,来营造一种散漫自由的风格。

skew() 方法的参数可以是:

  • 1个参数: 元素沿水平方向扭曲
  • 2个参数: 第一个参数为水平方向的扭曲度,第二个为垂直方向。

扭曲的单位只可以是角度(angle),即deg

@keyframes skewing {
  0%  { transform: skew(0deg);}
  20% { transform: skew(10deg);}
  40% { transform: skew(45deg);}
  60% { transform: skew(90deg);}
  80% { transform: skew(120deg);}
  100%{ transform: skew(0deg);}
}
p{ animation: skewing 10s steps(1) 0s infinite;}

skew(0deg): 没有变形

skew(10deg): 水平方向的轻度扭曲

skew(45deg): 1/4扭曲

skew(90deg): 1/2扭曲,元素的4条边被扭曲到了同一条线上,元素高度变为0,不可见

skew(120deg): 和 -60deg 的扭曲一样

Skewing

我们可以看到扭曲10度,是偏向负x轴。在扭曲过程中原点是固定,里面的文字出现了难看的变形。

三维变换(3d functions)

上述变换都是基于2D平面的,实际上这些方法都有一个3D版本

比如,translate() 的3D版本是 translate3d(),除了x,y方向外,还支持z方向上的位移。(因此也有一个对应的 translateZ() 方法)。

z 参数其实就是把元素拉近还是推远,视觉效果上和放大、缩小类似。

@keyframes zooming {
  0%  { transform: translate3d(0, 0, 0);}
  100%{ transform: translate3d(0, 0, 200px);}
}
p{ animation: zooming 5s alternate;}
Original

Transformed

绿色的区块将被拉近 200px。看起来像是被放大了一般。

你可以自己试一试

由于3d效果需要有一个虚拟的3d视觉空间,因此要呈现3d效果的元素的包容块(其父元素)中需要设置视角属性 perspective: 500px;,这样才可以激活3d视觉空间。我们也可以使用 transform: perspective(500px);

父元素中还设置了2个和3d变换有关的参数,分别是transform-style 和 perspective-origin,这两个参数是可选的。当设置了perspective时,transform-style将被设置为preserve-3d。

3D建模的关键因素有3个:视角、空间和物体。其原理可参考阅读如下博文玩转CSS3 3D - 原理篇

变换原点(transform-origin)

transform-origin是变换原点,也就是该元素围绕着那个点变形或旋转,该属性只有在设置了transform属性的时候起作用。

元素默认变换原点就是其中心位置,transform进行的rotate,translate,scale,skew,matrix等操作都是以元素自己中心位置进行变化的。

有时候我们需要在不同的位置对元素进行这些操作,那么我们就可以使用transform-origin来对改变元素变换原点(参照点)位置。

其语法是transform-origin(x,y),其中X和Y的值可以是百分比,em,px,其中x也可以是字符参数值left,center,right;y和x一样除了百分比外还可以设置字符值top,center,bottom。

这里有一个可视化的在线动画演示来帮助理解transform-origin对transform操作的直观影响(你可以直接拖动盒子两边的黄色箭头):

网页性能

translate所实现的功能和top/left修改元素位置完全相同,我们推荐使用translate方法而不是修改top/left值。因为使用CSS3 translate变换,将触发创建位于GPU中的独立渲染层,从主页面中脱离出来,不占用CPU,不会导致页面重布局(reflow或称之为relayout)。 这样其渲染性能将得到很大的提升。当然凡事有利有弊,对于大量(成千上万)粒子平移的动画,过度使用translate会导致复合(Composite)各渲染层的时间大为增加,从而得不偿失。更为详细的描述,请阅读这篇博客