详解CSS的矩阵变换函数matrix()

本文并不会讲解矩阵运算,也不会讲解矩阵变换的几何意义,那将是一个数学展开,颇为无味枯燥。话说大学修过线性代数的人应该都已经学过了,如果忘了,找本线性代数教科书看看就行。下文仅仅给出 CSS 矩阵变换函数的语法,以及其与对应的变换矩阵、变换函数间的联系。

矩阵变换的原理

在 2D变换 中,矩阵变换函数 matrix() 接受 6个值,语法形式如下:

1
E { transform: matrix(a, b, c, d, e, f); }

这相当于,对元素应用一个如下的变换矩阵:

$$
\begin{bmatrix}
a & c & e \
b & d & f \
0 & 0 & 1 \
\end{bmatrix}
$$

那么这个变换矩阵是如何被用来对元素进行几何变换的呢?

假设变换原点 transform-origin 的坐标是 $(0, 0)$,元素所呈现出来的几何图形中任意一点的坐标是 $(x_i, y_i)$,那么所谓的根据变换矩阵进行变换就是使用这个点的坐标 $(x_i, y_i)$ 的向量矩阵:

$$
\begin{bmatrix}
x_i \
y_i \
1 \
\end{bmatrix}
$$

与变换矩阵相乘:

$$ \begin{bmatrix}
a & c & e \
b & d & f \
0 & 0 & 1 \
\end{bmatrix}
\begin{bmatrix}
x_i \
y_i \
1 \
\end{bmatrix} = \begin{bmatrix}
ax_i + cy_i + e \
bx_i + dy_i + f \
1 \
\end{bmatrix}
$$

相乘所得到的矩阵向量就是点 $(x_i, y_i)$ 进行变换之后的新坐标:

$$
\begin{bmatrix}
ax_i + cy_i + e \
bx_i + dy_i + f \
1 \
\end{bmatrix}
$$

即根据变换矩阵进行变换之后点 $(x_i, y_i)$ 的坐标是 $(ax_i+cy_i+e, bx_i+dy_i+f)$。

在 2D变换中,变换总共有以下几种操作:

  • 平移:transform: translate(X, Y)
  • 旋转:transform: rotate(θ)
  • 倾斜:transform: skew(α, β)
  • 缩放:transform: scale(scaleX, scaleY)

这些对应的变换矩阵分别如下:

平移

对某一元素应用旋转变换 translate(X, Y),相当于对其应用如下变换矩阵:

$$
\begin{bmatrix}
1 & 0 & X \
0 & 1 & Y \
0 & 0 & 1 \
\end{bmatrix}
$$

即等价于使用矩阵变换函数 matrix(1, 0, 0, 1, X, Y)

旋转

对某一元素应用旋转变换 rotate(θ),相当于对其应用如下变换矩阵:

$$
\begin{bmatrix}
\cos\theta & -\sin\theta & 0 \
\sin\theta & \cos\theta & 0 \
0 & 0 & 1\
\end{bmatrix}
$$

即等价于矩阵变换函数 matrix(cosθ, sinθ, -sinθ, cosθ, 0, 0)

倾斜

对某一元素应用倾斜变换 skew(α, β),相当于对其应用如下变换矩阵:

$$
\begin{bmatrix}
1 & \tan\alpha & 0 \
\tan\beta & 1 & 0 \
0 & 0 & 1 \
\end{bmatrix}
$$

即等价于使用矩阵变换函数 matrix(1, tanβ, tanα, 0, 0)

缩放

对某一元素应用缩放变换 scale(scaleX, scaleY),相当于对其应用如下变换矩阵:

$$
\begin{bmatrix}
scaleX & 0 & 0 \
0 & scaleY & 0 \
0 & 0 & 1 \
\end{bmatrix}
$$

即等价于使用矩阵变换函数 matrix(scaleX, 0, 0, scaleY, 0, 0)

实际应用

为什么有直接诸如 rotate(θ) 这些简单可用的变换函数,我们还需要 matrix() 这么复杂的东西呢?

这里实际上有两个原因:

  1. 用 CSS 组合实现各种变换,在配合 JavaSCript 使用时,最经常遇到的是使用 JavaScript 改变部分属性值,会覆盖所有的原始变换的问题

  2. 在浏览器中获取 CSS 样式时,我们获取 transform 的属性值时实际上返回的是矩阵变换函数 matrix(a, b, c, d, e, f),并不是单一的变换函数。(!!!注意