Ver en Español
Everything about CSS transitions
Apr 13, 2023
Updated: Jun 25, 2026

Everything about CSS transitions

Transitions are part of the toolset we have as frontend developers to improve the user experience inside our web app. They are useful because they let us animate the change of values across an element's properties, which can make it more eye catching and invite the user to interact with it. In this post we'll cover the broad topic of transitions with several examples adapted from the specification.

Let's start with a simple example

We have a simple square:

<div id="square1" class="square red"></div>

And some styles associated with that square:

/* Defines the style rule for the "square" class */
.square {
  /* Sets the width to 50 pixels */
  width: 50px;
  /* Sets the height to 50 pixels */
  height: 50px;
  /* Sets a bottom margin of 5 pixels */
  margin-bottom: 5px;
}

/* Defines the style rule for the "red" class */
.red {
  /* Sets the background color to red */
  background: red;
}

We also have an additional class that we'll assign to the square at a specific point in time:

/* Defines the style rule for the "black" class */
.black {
  /* Sets the background color to black */
  background: black;
}

However, we want this change to happen in a smooth, controlled and pleasant way for the user. So this is where we need to make use of transitions. We can do this by adding the transition property inside the class we want to apply:

/* Defines the style rule for the "black" class */
.black {
  /* Sets the background color to black */
  background: black;
  /* Sets a transition for the "background" property */
  transition: background 2s 0.25s;
  /*          ^^^^^^^^^^ ^^ ^^^^^ */
  /*          Property   Duration  Delay */
}

The transition property lets the change of background from red to black happen over 2 seconds (duration) instead of happening instantly. It also lets us indicate that this change should start 0.25 seconds after the class is assigned to the element (delay). There's an alternative syntax for this that takes a few more lines, but it's useful to know:

/* Defines the style rule for the "black" class */
.black {
  /* Sets the background color to black */
  background: black;
  /* Sets the property that will be animated in the transition, in this case "background" */
  transition-property: background;
  /* Sets the duration of the transition, in this case 2 seconds */
  transition-duration: 2s;
  /* Sets the wait time before starting the transition, in this case 0.25 seconds */
  transition-delay: 0.25s;
}

By mastering CSS transitions you'll be able to improve the user experience in your web apps and achieve more appealing, dynamic effects.

Value analogies in CSS transitions

Just as we assigned values in seconds to the duration and the delay, we could have done it in milliseconds (ms). To do that, we'd just multiply by 1000 and add ms at the end. For example:

/* Sets the transition duration to 2000 milliseconds (2 seconds) */
transition-duration: 2000ms;

/* Sets a delay before the transition starts of 250 milliseconds (0.25 seconds) */
transition-delay: 250ms;

If we want to apply transitions to more than one property, we can use all to indicate that the transition applies to every possible property:

/* Defines the style rule for the "black" class */
.black {
  /* Sets the background color to black */
  background: black;
  /* Sets the text color to white */
  color: white;
  /* Sets a transition for every property change. */
  /* The duration is 2 seconds and it's delayed 0.25 seconds before starting */
  transition: all 2s 0.25s;
}

Note: Using transition: all is not recommended from a performance standpoint. It's strongly recommended not to use transition: all unless you definitely want to apply transitions to every property of the element in the same way. Next I'll explain how to make transitions specifically for each property.

Sometimes we don't want transitions applied to every property in the same way. The transition property also lets us specify the transition for each property simply by separating them with commas. Let's look at an example:

/* Defines the style rule for the "black" class */
.black {
  /* Sets the background color to black */
  background: black;
  /* Sets the text color to white */
  color: white;
  /* Defines a separate transition for the background and for the text color */
  transition:
    /* A 2 second transition for the background with a 0.25 second delay */
    background 2s 0.25s,
    /* A 1.5 second transition for the text color with a 3 second delay */
    color 1.5s 3s;
}

In the example above we are changing the background and the color with different durations and different delays. This gives us more granular control over exactly what we need to animate in each transition.

The timing function: transition timing function

So far the transitions we've talked about happen linearly, that is, the change happens uniformly over the time the transition lasts. However, that's not the only way to do it. We can speed up the change at the start and slow it down at the end, which gives us a different feel when watching the transition. To determine how the change will happen, we have the transition-timing-function property, which can take the following values:

/* "linear": the transition speed is constant throughout the whole animation */
transition-timing-function: linear;

/* "ease-in": the transition speed increases gradually at the start of the animation */
transition-timing-function: ease-in;

/* "ease-out": the transition speed decreases gradually at the end of the animation */
transition-timing-function: ease-out;

/* "ease-in-out": the speed increases gradually at the start and decreases gradually at the end */
transition-timing-function: ease-in-out;

/* "cubic-bezier": a custom curve defined by the given control points */
transition-timing-function: cubic-bezier(0.21, 0.3, 0.1, 0.23);

But this isn't the only way to add this property to transitions. It's also possible to do it directly on the transition property:

/* Defines the style rule for the "move" class */
.move {
  /* Moves the element 500 pixels along the X axis */
  transform: translateX(500px);
  /* Sets an animated transition for the transform property */
  transition: transform 2s 0.25s ease-in-out;
}

Or even on each individual property transition:

/* Defines the style rule for the "move-background" class */
.move-background {
  /* Moves the element 500 pixels along the X axis */
  transform: translateX(500px);
  /* Sets the background color to red */
  background: red;
  /* Sets a separate transition for transform and for background, each with its own timing function */
  transition: transform 2s 0.25s ease-in-out, background 1s 0.1s cubic-bezier(0.21, 0.3, 0.1, 0.23);
}

Understanding cubic bezier()

Let's dig a little deeper into how the transition-timing-function property works when it takes the value of cubic-bezier(). To do that, let's review what the Bézier curve this function is based on actually is.

Bézier curves are a mathematical system developed by Pierre Bézier for tracing drawings of aircraft and cars. The CSS cubic-bezier() function takes four numbers:

cubic-bezier(x1, y1, x2, y2);

Those four values are the coordinates of the two intermediate control points, P1 (x1, y1) and P2 (x2, y2). The other two points of the curve, P0 and P3, are fixed at (0, 0) and (1, 1) respectively, so they aren't passed as arguments. With the coordinates of P1 and P2 you can fully define the shape of the curve and therefore different kinds of transitions.

On these websites you can experiment more with this kind of transition, where you can adjust the values to get more control over your curve:

Keep in mind that there are properties that are not animatable, that is, you can't apply transitions to them. To see a list of which properties are animatable and which are not, you can check this MDN link:

Note: the official list lives on MDN under "Animatable CSS properties". That page explains the animation types; to check whether a specific property is animatable, look at the "Animation type" row in the "Formal definition" table on its reference page.

The following example shows a set of transitions on cubes with different transition-timing-function values and properties. You can play with them to see their differences:

Debugging transitions

Browser developer tools, like those in Chrome and Firefox, let us slow down or speed up transitions to debug them more easily. To do that, you can open the animations tab.

You can also use JavaScript to know the state of a transition through the following events:

  • transitionstart
  • transitionend

A few considerations

Finally, a few considerations about transitions:

  • Transitions around 100ms are practically instant to users and barely perceptible.
  • Transitions of at most 1 second and at least 250ms are good and keep users engaged.
  • More than 2 seconds is definitely a bad idea for standard websites, since it can disconnect the user from what's happening.
  • 250ms to 300ms is the standard duration of most animations.
  • Transitions, in general, let you create experiences that happen only once.
  • If the browser doesn't support transitions, in the worst case the property always changes directly.
  • Transitions are granular because they let you animate one, two, or multiple properties.

Suggested exercises

  1. Create a square that changes color and size on hover using a single transition with transition: all, then refactor it to animate each property separately.
  2. Experiment with transition-timing-function by applying ease-in, ease-out and ease-in-out to the same element and compare the feel of each one.
  3. Create your own curve at cubic bezier.com and apply it to a transform: translateX() transition.
  4. Use the transitionstart and transitionend events in JavaScript to log to the console when a transition starts and ends.

3-point summary

  1. The transition property (and its variants transition-property, transition-duration, transition-delay and transition-timing-function) animates the change of a property's values in a smooth, controlled way.
  2. Avoid transition: all for performance reasons; prefer declaring each property separately, separating them with commas.
  3. cubic-bezier(x1, y1, x2, y2) defines the curve with the coordinates of control points P1 and P2 (P0 and P3 are fixed at (0,0) and (1,1)), giving you full control over the feel of the transition.

That's all. I hope this post is useful to you and that you can apply it to a project you have in mind, or that it simply helped you understand the nature of CSS transitions.

Leave me a comment if you got it working, if you want to add some other feature, or if you have any questions. And remember, if you liked it, you can also share this article using the social links below.

Good luck with your projects, and don't forget to keep experimenting and learning about CSS transitions!

Sebastian Gomez

Sebastian Gomez

Creador de contenido principalmente acerca de tecnología.

Leave a Reply

0 Comments

Advertisements

Related Posts

Categorias