Use the transform CSS property to ensure smooth animations (2024)

It slices! It dices!

You’ve just seen that if you want smooth animations, you have a whopping two properties to choose from. And, on the surface, that might seem a bit...stifling.

I mean, how much can youreally do with just thetransformandopacityproperties?

But, really, the question isn't what you can do with just those two properties, but what can't you do with them?!

No, really!

You see, thetransformproperty packs a lot of punch for a single property. In fact, it has more than 20 different functions that you can use to move, scale, rotate, and distort elements.

In previous chapters,we usedtransformto change the scale of a button and circle. So, you’re familiar with its syntax and basic functionality.

.btn { &:hover + .ball{ transform: scale(1); }}

To harness the full power of thetransformproperty, we’re going to use more than a single function. Things can get tricky with multiple functions.

In this chapter, we’ll take a look at our go-totransformfunctions and the ins and outs of chaining them together to create animations that are more complex in nature, while still playing back at a smooth 60 frames per second.

Scale

To use thetransformproperty on an element, you need to supply it with the function (or functions, as you’ll see shortly) that perform the desired transformations. For example, to scale an object to 200% of its original size, use thescale()function with an argument of 2:

.btn { &:hover + .box { transform: scale(2); }}.box { transition: transform 330ms ease-in-out;}

Rather than supplyscale()with percentages, pass it numbers, where 0 is equal to 0%, and 1 is equal to 100%. So scale(2) scales the element to 200% of its original size:

Use the transform CSS property to ensure smooth animations (1)

Passing a single argument to thescale()function changes the size of an element uniformly, scaling both the height and width by the same amount. But you can also pass two arguments, one to scale the width, or X dimension, and one to scale the height, or Y dimension, individually.

Let’s say that we wanted to stretch the box, width-wise, and make it shorter at the same time to preserve its volume. Let’s change the X scale to 300% and Y scale to 50%:

.btn { &:hover + .box { transform: scale(3, 0.5); }}.box { transition: transform 330ms ease-in-out;}

Now the box stretches out horizontally:Use the transform CSS property to ensure smooth animations (2)

What if I only wanted to scale the box in one direction?

Youcould do something like:

.btn { &:hover + .box { transform: scale(2, 1); }}.box { transition: transform 330ms ease-in-out;}

Which works… it’ll scale the X-axis by 200% and the Y-axis by 100%... But there’s a cleaner and more explicit way to do the same thing. When you only want to scale in one direction, make use of the scaleX()andscaleY()functions. As you might have guessed,scaleX()scales an object horizontally, andscaleY()scales vertically.

So, to scale the button by 200% horizontally, usescaleX(2):

.btn { &:hover + .box { transform: scaleX(2); }}.box { transition: transform 330ms ease-in-out;}

Use the transform CSS property to ensure smooth animations (3)

But, like I said earlier, scaling is just one of transform’s many talents. Animation is dominated by three main types of transformations – position, scale, and rotation.You have scale down cold, so let’s take a look at position.

Position

Changing an object’s position can be done usingtransform’s translate()function. translate() accepts two arguments, the first being how far you want to move it in the X-axis, and the second is the distance to translate on the Y-axis. The values can be real units, such as px or vh, so you can move the box150pxto the right and up7vh like so:

.btn { &:hover + .box { transform: translate(150px, -7vh); }}.box { transition: transform 330ms ease-in-out;}

Use the transform CSS property to ensure smooth animations (4)

But translates are also assigned by percentage. Where other properties use percentages in relation to their parent element, such as width: 50% being half of the width of its parent:

Use the transform CSS property to ensure smooth animations (5)

When you use percentages withtranslate(), they are in relation to the element itself. Let’s say that you have an element that is 100px wide:

.btn { &:hover + .box { transform: translate(100px, 0); }}.box { width: 100px; height: 100px; transition: transform 330ms ease-in-out;}

If you translate it by 100% on the x-axis, it will move 100px to the right:

Use the transform CSS property to ensure smooth animations (6)

Just likescale(), you can transform elements in the x-axis and y-axis individually, using the translateX()andtranslateY()functions respectively. Let's add some texttothe box and have it scroll into view:

<div class="container"> <button class="btn">Transform!</button> <div class="box"> Boop! </div> </div>

Structurally, the markup is fine, but to animate the text separate from its parent element,you need to wrap it in some sort of element. So lets put it in a<span>:

<div class="container"> <button class="btn">Transform!</button> <div class="box"> <span>Boop!</span> </div> </div>

<span>gives thetransformproperty something it can grab onto and manipulate. Now let’s set up ourtransformto use translateY()so the text starts outside of the box and scrolls in:

.btn { &:hover + .box { transform: scale(1); span { transform: translateY(0); } }}.box { transform: scale(0.1); transition: transform 330ms ease-in-out; overflow: hidden; span { display: inline-block; transform: translateY(250%); transition: transform 280ms ease-out 50ms; }}

Notice that we’ve changed the display mode toinline-block? Transform can’t manipulate inline elements, like <span>, soyou need to change their display mode toblockorinline-block before you will see any results. We've also given the span transition a small delay and shortened its duration so it acts as a secondary animation (principle of animation #8 FTW! 🤘).

Use the transform CSS property to ensure smooth animations (7)

We've also added theoverflowpropertyto the span's parent, .box, and set it tohiddenso you don't see the text before it has scrolled into view.

Rotation

Now that we’ve covered animating position and scale, all that’s left of the big-three is rotation, whichtransformperforms with the aptly titledrotate()function.

You can supply values torotate()in a few different units, but only two of them are user-friendly/comprehensible by humans. And since we're humans, let's stick with those two.

The most obvious and straightforward is to use degrees, annotated with deg: rotate(360deg). You can also use turns, where one turn is equal to 360 degrees:rotate(1turn). To demonstrate, we have two boxes, each with their own modifiers for the rotation units used:

<div class="container"> <button class="btn">Transform!</button> <div class="boxes"> <div class="boxes__base boxes--rotDegrees">rotate(360deg)</div> <div class="boxes__base boxes--rotTurns">rotate(1turn)</div> </div></div>

Notice how the two boxes are nested within the.boxesdiv? Remember that to animate the properties of other objects in CSS they need to be the next sibling in the hierarchy. Now let's select the individual boxes and animate them independently:

.btn { &:hover + .boxes { & > .boxes--rotDegrees { transform: rotate(0deg); } & > .boxes--rotTurns { transform: rotate(0turn); } }}.boxes { &--rotDegrees { transform: rotate(-360deg); transition: transform 500ms ease-in-out; } &--rotTurns { background: pink; transform: rotate(-1turn); transition: transform 500ms ease-in-out; }}

Start with each box rotated negative 360deg/1turn and, upon triggering the transition with the button, rotate back to 0deg/0turn over the course of one half of a second using the ease-in-out timing function.

Use the transform CSS property to ensure smooth animations (8)

The end result is the exact same, and using degrees or turns comes entirely down to personal preference.

C-C-C-combo

Let’s give the animation a twist as it transitions by adding atransformproperty with the rotation()function to the box:

.btn { &:hover + .box { transform: scale(1); transform: rotate(0deg); span { transform: translateY(0); } }}.box { overflow: hidden; transform: scale(.1); transform: rotate(-90deg); transition: transform 330ms ease-in-out; span { transform: translateY(250%); transition: transform 280ms ease-out 50ms; display: block; }}

Now the circle should twist a quarter of a turn, from -90deg to 0deg, as it scales up and the text slides in. Check it out:

Use the transform CSS property to ensure smooth animations (9)Gah! 😱 We broke it!

It’s twisting, but the scale animations have disappeared. It looks like therotate()transform is overriding thescale()transform.

Let’s comment out therotate()transform and make sure we didn’t accidentally mess up thescale():

.btn { &:hover + .box { transform: scale(1); // transform: rotate(0deg); span { transform: translateY(0); } }}.box { overflow: hidden; transform: scale(.1); // transform: rotate(-90deg); transition: transform 330ms ease-in-out; span { transform: translateY(250%); transition: transform 280ms ease-out 50ms; display: block; }}

Use the transform CSS property to ensure smooth animations (10)

Okay,scale() still works just fine. So that must mean that only one transform property can be assigned to an element. Good to know! 😉

How do you perform multiple transformations within a singletransformproperty then?

Simple. Just list out all of the transform functions that you want to use within the transform property.

To add the twist to the scalingtransform, append therotate()function to thetransform property after thescale()function:

.btn { &:hover + .box { transform: scale(1) rotate(0deg); span { transform: translateY(0); } }}.box { overflow: hidden; transform: scale(.1) rotate(-90deg); transition: transform 330ms ease-in-out; span { transform: translateY(250%); transition: transform 280ms ease-out 50ms; display: block; }}

Now the box should twist as it scales up:

Use the transform CSS property to ensure smooth animations (11)

Success! Virtual high-five! 🤚

The order of rotation and scale won’t set off any alarms because they don’t directly affect each other. A 90-degree turn, then scaling to 200%, versus scaling to 200% and then rotating 90 degrees, will produce the same result.

Scale and translate, on the other hand? That’s a whole different story. Moving an element 200% and then scaling it up 200% produces a very different effect than scaling and then translating:

.btn { &:active + .box { & > .box__base--tranxScale { transform: translateX(200%) scale(2); } & > .box__base--scaleTranx { transform: scale(2) translateX(200%); } }}.box { &__base { &--tranxScale { background-color: #15dea5; transition: transform 330ms ease-in-out; } &--scaleTranx { background-color: pink; transition: transform 330ms ease-in-out; } }}

Box #1has the.box__base-tranxScalemodifier applied, and when triggered will apply the scale()transformation, followed bytranslateX().

Box #2 has.box__base--scaleTranx()assigned and will apply thetranslateX()transformation, followed by thescale():

Use the transform CSS property to ensure smooth animations (12)

Box #2 moves way further to the right than box #1. Twice as far, in fact. That’s because not only is the browser executing the transform functions in order, it’s using the original layout as the origin for the transformations.

If you were to break down transform’s order of operations into separate animations, you would see box #1 scale up to 200% and then move right 200% of the original dimension of the box:

Use the transform CSS property to ensure smooth animations (13)

But with box #2, the box moves the same distance of 200%, but rather than scaling up from the center of the box’s new position, it scales outward from the box’s original center, before translateX()was applied:

Use the transform CSS property to ensure smooth animations (14)

Box #2 moved to the right 200%, and then that translate was effectively doubled by the scale, making it appear to have moved 400% to the right.

Skew you

Position, scale, and rotation. Transform packs are a pretty decent arsenal.

But wait, there’s more! That’s right. If you order now, we’ll throw in theskew()function as well! Call now!

Just like position and scale,you can choose to skew objects horizontally or vertically by tilting the horizontal or vertical edges, or both, by using theskewX(), skewY(), andskew()functions respectively:

.box { &--skewX { transform: skewX(45deg); } &--skewY { transform: skewY(45deg); } &--skew { transform: skew(45deg, 45deg); }}

Use the transform CSS property to ensure smooth animations (15)

A whole other dimension

And that’s about it for transforms abilities… in 2D.

Yup! There’s a whole other dimension to play with! 😄 The functions for three dimensional transformations are quite similar to their 2D counterparts, only with the ability to transform along the z-axis as well. Here’s a quick rundown of the 3D functionsintransform's arsenal:

Use the transform CSS property to ensure smooth animations (16)

While the 3D functions look a lot like their 2D counterparts, you might have noticed a new function used throughout the 3D transforms: perspective().

The set value forperspective()tells the browser how far away the viewer is from the action. Just like in the physical world, the closer an object is, the more drastic motion will seem, while further away objects will seem more static.

.box { &--perspective75px { transform: perspective(75px) rotateX(45deg); } &--perspective150px { transform: perspective(150px) rotateX(45deg); } &--perspective300px { transform: perspective(300px) rotateX(45deg); }}

With a perspective of 75px, you are far closer to the box than with 150px or 300px. Thus, the 3D rotation appears far more drastic than the ones with more distant transforms.

Use the transform CSS property to ensure smooth animations (17)

You can use perspective and 3D transforms to add depth and visual effects to animations, such as parallax or even Hitchco*ck’s Vertigo dolly-zoom:

Having thetransformproperty in your toolbox lets you manipulate and animate your sites in nearly any wayyou could hope for, and, because it all takes place in the composite stage, you can be confident that they’ll playback smoothly, no matter the device.

Coming up next, we’ll take a look at a complimentary property that lets you expand the diversity of your transformations by moving their origin points.

Let's recap!

  • Thetransformproperty accepts functions with arguments as values.

  • Youcan move elements with the translate functions: translate(), translateX(), translateY(), andtranslate3d().

  • Youcan scale them with the scale functions:scale(), scaleX(), scaleY(), and scale3d().

  • And youcan rotate them with the rotate functions: rotate(), rotateX(), rotateY(), and rotateZ().

  • A selector can only have onetransformproperty.

  • Ifyou add a secondtransformproperty, it will cancel the first.

  • A transform property with multiple functions will execute the functions in order from right to left.

Use the transform CSS property to ensure smooth animations (2024)
Top Articles
Latest Posts
Article information

Author: Tish Haag

Last Updated:

Views: 5923

Rating: 4.7 / 5 (67 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Tish Haag

Birthday: 1999-11-18

Address: 30256 Tara Expressway, Kutchburgh, VT 92892-0078

Phone: +4215847628708

Job: Internal Consulting Engineer

Hobby: Roller skating, Roller skating, Kayaking, Flying, Graffiti, Ghost hunting, scrapbook

Introduction: My name is Tish Haag, I am a excited, delightful, curious, beautiful, agreeable, enchanting, fancy person who loves writing and wants to share my knowledge and understanding with you.