Why doesn't my scale3d() / scaleZ() transform work?
One of the trickier parts of 3D transforms is understanding how the
scaleZ()
and scale3d()
functions work. When applied to an element,
they will often appear to have no effect. But then at other times, or in
other combinations, they will. Confusing right?
So what's going on? Well, it has to do with transformation matrices, these bits of mathematical goodness that allow us to change where points are plotted within a coordinate system — in this case, your document viewport.
In May of 2013, I wrote an article for Dev.Opera about transform matrices. If you haven't read it yet, please do. It lays the groundwork for what I'm about to discuss here.
Coordinate systems
If you've ever taken algebra or geometry, you've probably learned about coordinate systems. You probably remember that the x-axis is horizontal, the y-axis is vertical, and the z-axis is perpendicular to them both.
If we move the coordinate system to our document viewport, our x axis goes from left-to-right on screen and the y axis goes from the top to the bottom. The z-axis sits perpendicular to the screen and viewer, but the screen itself is the 0 point of the z axis. Hold on to that point. We'll come back to it.
Coordinate vectors and matrix multiplication
Let's imagine that you have an object whose top left corner sits 100 pixels from the left edge of the document viewport, and 200 pixels from its top. This means its coordinates are (100,200,0) in a three dimensional system. It exists on the same plane as the screen, which as mentioned above, has a z-coordinate of zero.
Now let's say we wanted to scale our object along the z axis by a factor
of three — either scale3d(1,1,3)
or scaleZ(3)
. That, by the way, is
equivalent to matrix3d(1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,1);
. We need to
multiply our coordinate vector by our matrix as show in figure
1.
Notice anything weird about the product? It looks just like our coordinate vector. Because our z-coordinate value hasn't changed, our transform doesn't appear to be rendered on screen.
In other words, in order for a scaling transform along the z-axis to work, the matrix product of the transform must result in a z coordinate with a non-zero value.
Let's run the math on an example using
transform: rotateY(20deg) scale3d(1,1,10)
. First we need to multiply
our rotation matrix by our scaling matrix, as shown in figure
2.
This gives us a compound transform that we can then multiply by our coordinate vector from above ([100,200,0,1]) as we've done in figure 3.
Our product, [94,200,34,1] translates to a three dimensional coordinates of (94,200,34), and boom, our transform works as expected.