在 Chrome 104 中,支持了一个非常有意思的新特性。CSS 中的 transform
支持单独赋值改变。不要小看这一点,此点改动在很多时候,能够非常有效的解放生产力,算是一个非常 NICE 的更新。
浅析一下
什么意思呢?我们来看这样一个例子:
在之前,我们可以利用 transform 配合绝对定位的 top、left 进行任意元素的水平垂直居中,像是这样:
<div></div>
div {
width: 200px;
height: 200px;
background: #000;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
这样,我们就得到了一个水平垂直居中的元素:
但是,如果我们想对这个元素进行一个缩放的动画,该怎么做呢?会是这样:
div {
width: 200px;
height: 200px;
background: #000;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
@keyframes scale {
0% {
transform: translate(-50%, -50%) scale(1);
}
100% {
transform: translate(-50%, -50%) scale(1.2);
}
}
好的,动画本身,并不是重点。重点在于,在上述的 @keyframes 代码中,我们想改变的其实只有 scale() 的值,但是基于现有的 CSS 机制,我们必须把前面控制定位的 translate() 一并写上。
transform 拆开书写
为了解决这个痛点,规范支持了将 transform 分开书写的方式。
所以,对于这一句,transform: translate(-50%, -50%) scale(1),我们可以分别拆开成 translate 和 scale:
div {
width: 200px;
height: 200px;
background: #000;
position: absolute;
top: 50%;
left: 50%;
// transform: translate(-50%, -50%); 删掉这句
translate: -50% -50%;
scale: 1;
animation: scale 1s infinite linear alternate;
}
@keyframes scale {
0% {
scale: 1;
}
100% {
scale: 1.2
}
}
是的,我们可以通过 translate 和 scale 分开控制它们,这样我们就能愉快的在 @keyframes 中,只进行 scale 的动画了!妙哉。
所以,根据规范 -- [1],于 transform 而言,我们可以将它整个拆解为:
- translate
- rotate
- scale
具体的语法会有一点点不同,具体使用的时候,多看看文档,譬如 translate 接收 3 个参数,第 2、3 个参数如果不存在,则为零(例如:translate: 50% 50% 0)。又譬如 rotate,如果想改变 Y 轴的旋转角度,可以这样写 rotate: y 30deg。
再举个例子,下面两组代码是等效的:
// 上下两组代码产生的效果等效!
{
transform: translate(-50%, -50%) rotateZ(30deg) scale(1.2);
}
{
translate: -50% -50%;
rotate: Z 30deg;
scale: 1.2;
}
是的,比较奇怪的是,规范里没有涉及到 skew 的拆解。
顺序对 transform 的影响
当然。拆开后和原本写在一起并非完全一样。
如果,我们使用的是 transform,将它们全部写在一起,像是这样:
div {
transform: rotateY(90deg) translateZ(400px) scale(1.2);
}
此时,元素的 transform 变换遵循的是从左向右进行变换。也就是先旋转 rotate
,再 translateZ()
,最后缩放 scale()
。
但是如果,我们分开来写:
div {
rotate: Y 90deg;
translate: 0 0 400px;
scale: 1.2;
}
虽然代码属性的顺序是 rotate --> translate --> scale,但是实际上,无论他们的书写顺序如何,解析的时候都会按照首先 translate,然后 rotate,最后 scale 的顺序进行!
这个会有什么影响吗?当然,这里我们来看这样一个例子。假设,我们想实现这样一个立方体:
不算上下两个面,以其余 4 个面为例子,正常的做法是,在 transform-style: preserve-3d 状态下,每个面先绕 Y 轴旋转一定的角度,然后进行 translateZ() 的位移。
像是这样:
所以,代码会是这样:
face1 {
transform: rotateY(0) translateZ(200px);
}
face2 {
transform: rotateY(90deg) translateZ(200px);
}
face3 {
transform: rotateY(180deg) translateZ(200px);
}
face4 {
transform: rotateY(270deg) translateZ(200px);
}
注意,这里 transform 的变换是先旋转,再位移。
如果我们拆开写,变成:
face2 {
rotate: Y 90deg;
translate: 0 0 200px;
}
//...
则整个效果就变成了:
因为这里实际执行的顺序是,先 translate,后 rotate。
所以,实际使用的时候一定要注意,矩阵变换的顺序会影响最终的效果。如果对顺序有严格的要求,还是需要合在一起写。
总结一下
本文比较简单,没有复杂的 CSS 动效,主要介绍了从 Chrome 104 开始,transform 支持单独赋值这一更新。其中有三点需要注意:
- 于transform 而言,我们可以将它整个拆解为 translate、rotate、scale 的分开写法。
- 对于完整的transform 而言,其执行顺序遵循从左向右进行变换。
- 对于分开写的transform 而言,无论其书写顺序,总是按照先 translate,然后 rotate,最后 scale 的顺序进行!
最后
好了,本文到此结束,希望本文对你有所帮助 :)
参考资料
[1]W3 - individual-transforms: https://www.w3.org/TR/css-transforms-2/#individual-transforms。
[2]CodePen Demo -- 3D Box View: https://codepen.io/Chokcoco/pen/vYjpWBW?editors=0100。
[3]Github -- iCSS: https://github.com/chokcoco/iCSS。