Understanding CSS 3D-Transforms

3D transforms can be a bit of a mind-boggling concept at first, particularly given that the HTML canvas (your screen) is a 2D space. While most of us understand the most commonly used 3dtransform - transform: translate3d(x, y, z), there are other values that can effect 3D rendering such as rotate, backface-visibibility, perspective and lots more.

Let's take a look at better understanding the spectrum of css 3d transform properties.

Translate 3D

Ok so let's take a look at one of the most common CSS 3d transforms, the translate3d() value. The syntax (with browser prefixes) looks like this:

.object {
-webkit-transform: translate3d(x, y, z);
-moz-transform: translate3d(x, y, z);
-ms-transform: translate3d(x, y, z);
-o-transform: translate3d(x, y, z);
transform: translate3d(x, y, z);

Value units are most commonly entered in px, but you can also use em, rem, and %. To help better understand things, here's a quick CodePen I've created separating each axis value.


The CSS perspective: property sets an element's position in 3D-space by affecting the distance between the Z plane and the viewer.

The number-value defines the position . The smaller the value - the closer the element will appear to the screen (when transformed in 3d space). The greater the value, the farther away it will appear (when transformed in 3d space).

It's important to note that it will only have an effect when an element is or has been transformed using a 3d transform value. Furthermore, it only effects CHILD elements. So for it to have an effect on a given element, you would apply it to the parent.

The syntax is as follows:

.object {
-webkit-perspective: [n];
-moz-perspective: [n];
-ms-perspective: [n];
-o-perspective: [n];
perspective: [n];

This shouldn't be confused with the transform: perspective() transform which can be applied directly (and affects) the element being transformed. Both perspective: and transform:perspective() use a number value. However, perspective: will work both with, and without a unit value (px, em, rem, %). On the other hand, transform:perspective() must have a unit value to have any effect.

.onject {
/*transform perspective*/

The best way of thinking of it is the strength of a 3D transform. The higher the perspective value, the less significant the transform. Again, here is another CodePen with the addition of the perspective property:

Note: If no perspective value is present on the parent, a 3D transform on the child will have no effect.

Rotate 3D

Let's now turn our attention to 3D rotations. In essence they follow the same principles of 3D translates and are also used on the CSS transform: property. However, when rotating along a single axis (e.g rotateX()), the value doesn't use any other unit other than degrees. So the value must be entered as [value]deg.

On the other hand, when using the rotate3d() property this changes. Infact, using rotate3d() is the only css transform that is longer to write in short-hand (3d), than long-hand (individual 2d).

Personally, I find it easier to stick to the individual values when rotating. There's a Stack Overflow answer here that explains the complexities of rotate3d() in further detail.

The syntax is as follows:

.object {

Here's a CodePen with the axes separated:

Back-face Visibility

The CSS backface-visibility: property has effect when an element is rotated so that its "back" is (or is not) visible. It has a value of either visible or hidden and is visible by default. The syntax is as follows:

.object {
-webkit-backface-visibility:hidden; /* Chrome, Safari, Opera */

And here's a CodePen where you can toggle it on/off to see how it works:

3D Scale

We can also scale elements with the CSS scale3d() transform. Again, it follows a similar theory to the others. Note that the scale value accepts only a single number without any units (em, rem, px ,%). The syntax is as follows:

.object {
-webkit-transform: scale3d(x,y,z);
-moz-transform: scale3d(x,y,z);
-ms-transform: scale3d(x,y,z);
-o-transform: scale3d(x,y,z);
transform: scale3d(x,y,z);

And here's a CodePen for a visual explanation with the axes separated. Note: I've added the rotateX() axis to help show what scaleZ() does.


We can also use the CSS transform skew() in 2D space. While it's not actually a 3D transform, I thought I should include it anyway. Like rotate, skew value-units must be entered in degrees [value]deg. The syntax is as follows:

.object {

And here's a CodePen:

Transform Origin

Lest we forget the CSS transform-origin: property. This sets the origin of the transform relative to the element being transformed. Importantly, values can be entered in em, rem, px, or %. By default, browsers set the transform origin of all transforms at 50% 50%, which is the center of the element being transformed. The syntax is as follows:

-webkit-transform-origin: x-axis y-axis z-axis ;
-moz-transform-origin: x-axis y-axis z-axis ;
-ms-transform-origin: x-axis y-axis z-axis ;
-o-transform-origin: x-axis y-axis z-axis ;
transform-origin: x-axis y-axis z-axis ;

and here's a CodePen:

Multiple Transforms

Mutiple CSS transforms need to be set under a single transform property. You can't use multiple CSS transform values on a single element under separate transform properties.

Meaning this will have no effect:

.object {
/*This is wrong and won't work.*/
transform: translateX(10px);
transform: translateY(10px);

You need to write it like this:

.object {
/*multiple transforms*/
transform: translateX(10px) translateY(10px);

Or like this:

.object {
/*multiple transforms*/
transform: translate3d(10px, 10px, 0);

Short-Hand and Long-Hand

Finally, let's take a look at short and long-hand syntax. As noted above, multiple transform values on a single element need to be set on a single transform property. However, there are two ways of going about things. All CSS transforms (rotate, scale, translate, skew) can be defined on their single axes (as seen in the demos on this page). Thus the long-hand way of creating a transform would be like this:

.object {
/*Long Hand*/
transform: translateX(20px) translateY(20px) scaleX(3) scaleZ(4);

However, if we use 3d transform syntax (short-hand) the code above would look like this:

.object {
/*Short Hand*/
transform: translate3d(20px, 20px, 0) scale3d(3, 0, 4);

With the exception of rotate3d(), which is actually longer to write than individual axis values. Also remember that when using 3d transforms, a perspective value must be present to take effect, even if you're only using 2d values in a 3d transform.

More Information

Share This Article


Woops, there was an error. Please try again soon.

Thanks, you've been subscribed!

You're already sucbscribed! Check your inbox.