Many moons ago, if web developers wanted to animate their websites, all they really had were gifs and marquee text. But now we have CSS transitions - and all is well with the world.

CSS transitions are the simplest way to create animations on your site. You can do some really cool stuff without a line of JavaScript, and they are pretty easy to learn. So let's do exactly that - here's your complete guide to CSS transitions.

What is a CSS Transition?

There are tons of situations where you'll want to dynamically change the CSS property of an element on your site. For example, maybe you want to change the background colour of a button when someone hovers on it. You could do that like this:

Create a button element:

<button>Submit</button>

Add some CSS:

button {
border: 3px solid #F4D06F;
border-radius: 10px;
width: 100px;
height: 50px;
font-family: sans-serif;
font-size: 20px;
background: #392f5a;
color: #F4D06F;
}

button:hover {
background: #F4D06F;
color: #392f5a;
}

And you get this:

See the Pen on CodePen.

We changed the background and color properties using the :hover selector, so when you hover on the button these properties are applied. But notice that they are applied instantly. It's a little jarring. Wouldn't it be cool if there was a way to change gradually from one state to the other, to... transition... between them...

Let's try that again, with a CSS transition...

An astute reader like yourself will already have figured out that there is a way to do that. And it only takes one line of code, added to the CSS for the button:

transition: 1s;

That creates this:

See the Pen on CodePen.

Much nicer!

This makes the transitions between the colours take 1 second - but you can set that to whatever you want. You can use fractions of a second, like 0.5s, 0.1s, or milliseconds, e.g. 300ms, 500ms. So .25s and 250ms create the same result.

Try editing the pen, and setting some different values: 0.1s, 0.5s, 3s... which do you think works best? Why?

So, that's a transition at it's most basic. But you wouldn't be reading a complete guide to CSS transitions if there wasn't more to it!

In fact, that transition property actually combines four other CSS properties at the same time. These are:

  • transition-duration
  • transition-property
  • transition-timing-function
  • transition-delay

Setting these all together using just the transition property is the preferred way to do it (you'll see why in a sec), but let's go through each of these in turn so you know what they do and how to use them.

CSS transition-duration

You've already seen how this one works in the example above - it controls how long the transition from one state to the other will take.

The default value for transition-duration is 0s. In other words, if you don't specify a duration, you won't get an animation. The element will just snap instantly from the first state to the second, like in the first button example.

CSS transition-property

With transition-property, you are able to control exactly which CSS properties of the element will be animated.

Let's get nuts and add a load more properties to our button's hover selector:

button:hover {
background: #F4D06F;
color: #392f5a;
width: 200px;
height: 100px;
font-size: 30px;
transform: rotate(360deg);
}

This will turn out like this:

See the Pen on CodePen.

First of all, please do not do this with your own buttons - there's such a thing as over-animating! But note how that 1-second transition applies to each property. That's because the default transition-property value is all - anything that can be animated, will be animated.

If you want to change multiple properties, but you don't want to animate all of them, you simply list them separately:

  transition: background 1s, color 2s;

In this case we've set the background to transition in 1 second, the colour to transition in 2 seconds, but nothing else will be transitioned. That creates this result:

See the Pen on CodePen.

Note how the width, height, and font-size change instantly - they don't transition. And we don't see the rotation at all because we rotated 360 degrees - so we just ended up back where we started.

If you're wondering exactly which properties you're able to animate with CSS transitions, Mozilla has a guide for that here.

Setting transition-duration and transition-property separately

If you set transition-duration and transition-property separately, you can still set unique durations for each property you want to animate - just list them separately:

  transition-property: background, color;
transition-duration: 1s, 2s;

And if you have more properties than durations, the browser will just repeat your duration values. So this:

  transition-property: background, color, width, height;
transition-duration: 1s, 2s;

Is equivalent to this:

  transition-property: background, color, width, height;
transition-duration: 1s, 2s, 1s, 2s;

However, it's much harder to read and maintain the code when you set these properties separately. So it's generally preferable to just use transition:

  transition: background 1s, color 2s, width 1s, height 2s;

Now it's much easier to see which duration belongs to which property, and it's easier to add and remove transitions without messing anything up.

CSS transition-timing-function

This is where things get really cool.

While transition-duration controls how long it takes to transition from one state to the next, transition-timing-function controls the speed of the transition within that time.

For example, if you're moving a box from one side of the screen to another, do you want it to move at a constant pace? Or do you want it to move quickly at first, but then slow down as it nestles into its finishing position? That's what transition-timing-function can do for you. There are five commonly used pre-set options:

  • linear: The transition happens at a constant speed.
  • ease: Starts off fast, but slows down just before the end. This is the default value.
  • ease-in: Start off slow, and gradually builds up speed.
  • ease-out: Starts off fast, but slows down early.
  • ease-in-out: Starts off slow, slows down early, but fast in the middle section.

This is easier to understand visually - hover over the image below to trigger the boxes to move:

See the Pen on CodePen.

As you can see, they all reach the finish line at the same time, but they move at different speeds along the way.

To do this, I absolutely positioned each box, gave each one a unique class, and then used that class to set the transition on the left property:

.linear {
transition: left 2s linear;
}

.ease {
transition: left 2s ease;
}

.ease-in {
transition: left 2s ease-in;
}

.ease-out {
transition: left 2s ease-out;
}

.ease-in-out {
transition: left 2s ease-in-out;
}

As noted before, you can assign these three values separately, for example, you could use this:

.ease-in-out {
transition-property: left;
transition-duration: 2s;
transition-timing-function: ease-in-out;
}

However you'll run into the same issues regarding readability and maintainability that we talked about earlier - so it's best to set them all together with transition.

Setting customised timing functions with cubic-bezier()

For most situations, these five values will probably have you covered. However, you can customise the acceleration and deceleration of your transition by using the cubic-bezier() function.

A cubic Bézier is a type of curve, named after French engineer Pierre Bézier, who used it to create the curves on Renault cars in the 1960s. The function takes four arguments, and from these, calculates a curve which determines the timing of the transition.

OK, that's a mouthful! What does it all mean? Well, let's first think about linear timing. If you plotted that on a chart it'd look like this:

Linear Timing Transition

The time the transition takes is along the x axis, and the progress of the transition (e.g. how far the box moves) is up the y axis. We see a straight line with linear, because the transition happens at a constant rate.

Now let's look at another one, ease:

Ease Timing Transition

As you can see here, most of the progress of an ease transition happens quite early. Halfway through the duration, 80% of the animation has already been completed. The final 20% of the animation takes the same amount of time, which gives that deceleration effect.

Each of the five 'pre-set' transition timings has their own curve, and you could re-create it using cubic-bezier() if you really wanted:

  • linear = cubic-bezier(0.0, 0.0, 1.0, 1.0)
  • ease = cubic-bezier(0.25, 0.1, 0.25, 1.0)
  • ease-in = cubic-bezier(0.42, 0, 1.0, 1.0)
  • ease-out = cubic-bezier(0, 0, 0.58, 1.0)
  • ease-in-out = cubic-bezier(0.42, 0, 0.58, 1.0)

And of course, you are completely free to create your own curve! Lea Verou has an excellent cubic bezier tool that you can play around with.

I'll say one more thing on this before we move on - in general, and especially with movement, you'll want to avoid linear. Objects accelerate and decelerate in the real world around us, so if we replicate that in our transitions, they'll feel more natural.

CSS transitions with steps()

Each of the above options creates a nice, smooth transition from one state to the next. But what if you don't want a smooth transition? What if you want to change state in a number of distinct stages? Well, you can use the steps() function for that:

  transition-timing-function: steps(10);

Or, like before, you can combine this into the transition property:

  transition: left 2s steps(10);

Here we're transitioning the left property, setting a transition-duration of 2 seconds, and we want it to happen in 10 discrete stages rather than one smooth movement.

The pen below shows what a few different steps() values look like in action - and I've put a linear timing function at the top for comparison:

See the Pen on CodePen.

Note that all transitions technically use steps. It's just that when we use ease or one of the other options, the browser is using so many steps that it appears smooth to the human eye. If you use a really high value with steps, like steps(240), it should be indistinguishable from the linear version.

CSS steps - do you need a jump start?

You might be thinking, if the transition takes five steps, does that include the starting point? For example, if we use steps(5), is the initial state of the element included in those 5 steps? Or does it make 5 steps from that point? For that matter, is the final state included? Or does it mean there are 5 intermediate steps between the beginning state and the ending state?

This is something you can choose for yourself, by passing a second argument, a jumpterm, to steps() along with the number of steps. You have a few options here (these examples assume you want 5 steps):

  • jump-start: The element will make five steps from the starting state to the end state. So there will be 6 stages in total. As soon as the transition begins, the element will immediately jump to the first step - a jump start!
  • jump-end: The element will make the exact same steps as jump-start, but it will reach the final stage exactly when the transition ends. This is a bit like ease-in - it will feel like a slow start. This is the default setting.
  • jump-none: The initial state and the end state are included in the 5 steps. So there will be 3 intermediate steps, between them, and the element will technically make 4 changes in total.
  • jump-both: The initial state and the end state are not included in the 5 steps. So there will be 5 intermediate steps between them, and the element will technically make 6 changes in total.

(note that you can also use start instead of jump-start and end instead of jump-end).

Let's see how these look! Using the same boxes as above, I've added a different class to each box, and applied a different jumpterm to each one, asking for 5 steps each time:

.no-jump-setting {
transition: left 2s steps(5);
}

.jump-start {
transition: left 2s steps(5, jump-start);
}

.jump-end {
transition: left 2s steps(5, jump-end);
}

.jump-none {
transition: left 2s steps(5, jump-none);
}

.jump-both {
transition: left 2s steps(5, jump-both);
}

And here's the result:

See the Pen on CodePen.

CSS transition-delay

The final transition property is transition-delay. As the name implies, this enables you to set a delay between when the transition is triggered, and when the animation actually begins.

You use it like this:

transition-delay: 1s;

To put it with every else in transition, you just add the delay to the end:

  transition: left 2s ease 1s;

Hover over the boxes to see a few different delays:

See the Pen on CodePen.

Note that the delay time is not included in the transition-duration. So a transition with a 2s duration and a 1s delay will take 3s in total.

Accessibility with transitions and animations

While many people will love all the awesome animations you're going to create, many others would rather do without them. In fact, on-screen movement can cause sickness and even seizures in some folk.

But you may have noticed that animations are all over the web now. So what do these people do? Do they just not use the internet?

No they do, but they change a setting in their OS to indicate that they would prefer reduced movement. Browsers detect this setting, and pass it to your site. You can then detect what their preference is, and use a prefers-reduced-motion media query to turn off your transitions:

@media (prefers-reduced-motion: reduce) {
.box {
transition: none;
}
}

You can simply list all elements with transitions in this query, and set transition to none as you see above. To be on the safe side though, you can approach this from the opposite angle:

@media (prefers-reduced-motion: no-preference) {
.box {
transition: background 2s ease-in-out 1s;
}
}

The no-preference value is the default for prefers-reduced-motion. So if you put all of your transitions in this query, your site will turn transitions on unless told not to. It's a safer option, just in case you or your colleagues forget to turn a transition off in the reduce query.

What will you create?

Congratulations! You now have the tools to create all manner of transitions for your website. Once you get to grips with this, you'll be amazed at what you're able to create.

If you want some inspiration, to see what's really possible, have a look at fullPage.js. fullPage enables you to create beautiful, fully-responsive, full page sites that run smoothly and provide an awesome experience for your visitors.

Check out these fullPage examples to see the different transitions, animations, and effects you can apply to your own site. There are different scroll effects, fades, parallax effects, and a range of different sliders. Give it a try!