A matrix is an array of numbers or expressions arranged in a rectangle of rows and columns. All transforms can be expressed using a 4*4 matrix.
This matrix corresponds to the matrix3d() function, which accepts 16 arguments, one for each value of the 4*4 matrix. Two-dimensional transforms can also be expressed using a 3*3 matrix, seen in the following image.
This 3*3 matrix corresponds to the matrix() transform function. The matrix() function accepts six parameters, one each for values a through f.
Each transform function can be described using a matrix and the matrix() or matrix3d() functions. The image below shows the 4*4 matrix for the scaLe3d() function, where sx, sy, and sz are the scaling factors of the X-, Y-, and Z-dimensions respectively.
When we combine transforms—such as transform: scaLe(2) transLate(30px, 50px) —the browser multiplies the matrices for each function to create a new matrix. This new matrix gets applied to the element.
But here’s the thing about matrix multiplication: it isn’t commutative. With simple values, the product of 3*2 is the same as 2*3. With matrices, however, the product of A*B is not necessarily the same as the product of B*A. Let’s look at the image below as an example, where we calculate the matrix product of transform: scaLe(2) transLate(30px, 50px) .
Our product results in a matrix that scales our element by a factor of two along the X- and Y- axes, and offsets each pixel in the element horizontally by 60 pixels and vertically by 100 pixels. We can also express this product using the matrix() function: transform: matrix(2, 0, 0, 2, 60, 100) .
Now let’s switch the order of these transforms—that is, transform: translate(30px, 50px) scaLe(2) . The result is shown below.
Notice that our object is still scaled by a factor of two, but now it’s offset by 30 pixels horizontally and 50 pixels vertically. Expressed using the matrix() function, this is transform: matrix(2, 0, 0, 2, 30, 50) .
It’s also worth noting that inherited transforms function similarly to transform lists. Each child transform is multiplied by any transform applied to its parent. For example, take the following code:
<div style=”transform: skewX(25deg)”>
<p style=”transform: rotate(-15deg)”></p>
This is rendered the same as the following:
<p style=”transform: skewX(25deg) rotate(-15deg)”></p>
The current transform matrix of the <p> element will be the same in both cases. Though we’ve focused on 2D transforms so far, the above also applies to 3D transforms. The third dimension adds the illusion of depth. It also brings some additional complexity in the form of new functions and properties.
Source: Brown Tiffany B (2021), CSS , SitePoint; 3rd edition.