Part of Series: CSS Handbook

CSS Transformations

📣 Sponsor

For most of CSS history, it only manipulated things on a 2D plain. Then, a new specification came on the scene talking about how we could continue to do this, and also move into the 3d dimension, with CSS transforms.

CSS Transforms are also a better way to move items around, since they are hardware accelerated. That means your computer will use your GPU to generate the movement is noticeably better with CSS transforms.

Simple translations

Let's start simple. CSS transforms support a number of values, and one of the most useful is translation. We can translate in a number of ways:

  • translateX(x) - translate along the x-axis.
  • translateY(y) - translate along the y-axis.
  • translateZ(z) - translate along the z-axis.
  • translate3d(x, y, z) - translate along all axis collectively.

As you might expect, translates accept distance values, i.e. 1rem, 1px, 1em, etc. Let's take a look at a quick example:

div > .transformed { transform: none; transition: transform 0.5s ease-out; } div:hover > .transformed { transform: translateX(10px) translateY(20px); }

We can separate multiple transformations with a space in transform. Notice how I have put the hover on the parent div. Why did I do that? Well, since the p is going to be moving, if the hover was on that, then the user wouldn't be hovering over the p anymore once it'd moved! This is a good practice, to ensure consistent experience for your user.

How it looks

Hover over me!

Comparison of transform and positioning

Just for fun, remember I said transforms and positioning used different processing? Here is a side by side example of how they compare. If you rapidly hover over this many time, you'll notice the boxes go out of sync. This is because of the difference in hardware acceleration.

This is a small change because these elements are very small and simple, but on very large objects this begins to become noticeable.

Hover over me!


We can also rotate items with the rotate functions. They are similar to the translation effects:

  • rotateX(x) - rotate along the x-axis.
  • rotateY(y) - rotate along the y-axis.
  • rotateZ(z) - rotate along the z-axis.
  • rotate3d(x, y, z) - rotate along all axis collectively.

For rotations, we use different units. We can use deg, rad or turn, referring to degrees, radians, or number of turns, respectively.

Here is an example:

I am rotateX(45deg)
I am rotateZ(1rad)


Finally, we can scale objects with scale. As with the previous options, we can do it along all 3 axis:

  • scaleX(x) - scale along the x-axis.
  • scaleY(y) - scale along the y-axis.
  • scaleZ(z) - scale along the z-axis.
  • scale(x, y, z) or scale(all) - scale along all axis collectively.

Scale accepts a number between more than 0. A number of 0.5 therefore would be 50% smaller than the original element, while 2 would be 2 times bigger.

A Real World Example

One of my favourite transition scale effects is the scale to show effect, or zoom to show modal effect. It looks like this in code:

<div class="modal"> I am a modal! </div>
.modal { transform: scale(0.001); opacity: 0; transition: transform 0.1s ease-out, opacity 0.1s ease-out; pointer-events: none; background: white; padding: 1rem; color: black; box-shadow: 0 2px 20px rgba(0,0,0,0.1); } { transform: scale(1); opacity: 1; pointer-events: all; }
I am a modal!

Preserve 3D

When you are working with multiple items transformed in 3D space in a specific container, you would expect that they would maintain a single 3D space. However, that is not the case. If you do not use transform-style, each item will retain an individual 3D space. By adding the following code to the container, you can make sure items will move through each other:

.container { transform-style: preserve-3d; }

Making a 3D Cube

Using a what we've covered, and preserve-3d, we can take a look at how we can create a cube. I've also added a button which removes or adds the preserve-3d property - so you can see how it affects the shape:

#cube-element { width: 200px; height: 200px; transform-style: preserve-3d; transform: rotateX(20deg) rotateY(10deg) rotateZ(10deg); } #cube-element > div { width: 100%; height: 100%; background: #5f86e240; position: absolute; } #cube-element .front { background: rgb(51 67 109 / 15%); transform: translateZ(100px); } .back { transform: rotateY(180deg) translateZ(100px); } #cube-element .right { background: rgb(51 67 109 / 15%); transform: rotateY(90deg) translateZ(100px); } #cube-element .left { background: rgb(51 67 109 / 45%); transform: rotateY(-90deg) translateZ(100px); } #cube-element .top { background: rgb(51 67 109 / 0%); transform: rotateX(90deg) translateZ(100px); } #cube-element .bottom { background: rgb(51 67 109 / 5%); transform: rotateX(-90deg) translateZ(100px); }
<div id="cube-element"> <div class="front"></div> <div class="back"></div> <div class="right"></div> <div class="left"></div> <div class="top"></div> <div class="bottom"></div> </div>
Last Updated 1644179540911

More Tips and Tricks for CSS

Subscribe for Weekly Dev Tips

Subscribe to our weekly newsletter, to stay up to date with our latest web development and software engineering posts via email. You can opt out at any time.

Not a valid email