skip to content

CSS: Transition Timing Functions

This article follows on from the related article on Animation using CSS Transforms and covers the transition-duration, transition-timing-function and other related CSS3 properties which affect the timing of animations.

The examples on this page will work in most modern browsers, including Internet Explorer 10, with no prefix. For some older browsers and mobile devices the -webkit-, -moz- and -o- prefixes may be required. Internet Explorer 9 and earlier have no support for CSS3 transitions.

Transition Timing Function Options

The transition-duration property is simple to understand. It defines the total duration of a transition from state A to state B, whether the transition involves scaling, distorting, rotating or modifying the style of an element.

The transition-timing-function is more difficult as it defines the rate at which the transition is carried out, which can involve speeding up and slowing down. It's all got something to do with Bézier curves as described here:

The transition-timing-function property describes how the animation will proceed over time. Keywords can be used for common functions or the control points for a cubic bézier function can be given for complete control of the transition function.

Rather than trying to work out what all that means, lets look at the keyword values for this property and how they affect a simple translation across the page. Move your mouse over the field below and the green boxes should all take off in a race across the page.

Each balloon has been assigned a different timing function controlling it's progression as it floats from the bottom of the box to the top. The labels show which of the named timing functions has been assigned, apart from the last balloon to which a custom timing function has been assigned, namely cubic-bezier(0,1,1,0), causing it to pause half way.


You can certainly see the effect of different transition timing functions on the animation. Of the named functions the ease-out box is fastest out of the blocks with ease-in lagging at the back. The default setting seems to be a slightly accelerated version of ease-in-out. And all of them complete the trip in the same 3 seconds. Here is the relevant HTML and CSS:

<style> .stable { position: relative; height: 320px; } .stable .balloon { position: absolute; bottom: 0; width: 100px; height: 163px; background: url(/images/balloon.png) no-repeat; } .stable:hover .balloon { bottom: 157px; transition-duration: 3s; } .stable .balloon.default { left: 39px; background-image: url(/images/balloon-blue.png); } .stable .balloon.linear { left: 149px; transition-timing-function: linear; } .stable .balloon.ease-in { left: 259px; transition-timing-function: ease-in; } .stable .balloon.ease-out { left: 369px; transition-timing-function: ease-out; } .stable .balloon.ease-in-out { left: 479px; transition-timing-function: ease-in-out; } .stable .balloon.cubic-bezier { left: 589px; transition-timing-function: cubic-bezier(0,1,1,0); } </style> <div class="stable"> <div class="balloon default">default</div> <div class="balloon linear">linear</div> <div class="balloon ease-in">ease-in</div> <div class="balloon ease-out">ease-out</div> <div class="balloon ease-in-out">ease-in-out</div> <div class="balloon cubic-bezier">cubic-bezier</div> </div>

expand code box

The cubic-bezier option let's you specify your own curve by defining two points. The curves used for the above display are illustrated in the next section, except for linear which I hope speaks for itself.

What are Bézier Curves?

The model used to generate different timing functions is based on cubic bézier curves which are described in the Surfin' Safari blog as follows:

To specify a cubic bezier function, you give an X and Y values for 2 of the control points of the curve. Point P0 is implicitly set to (0,0) and P3 is implicitly set to (1,1). These 4 points are used to compute a cubic bezier curve.

In the same article they provide the values used to generate the 'named' options which allow us to illustrate the different curves. Below each graph you can see the name of the timing function and the coordinates of P1 and P2 used to plot the curve. For the last curve we've defined the coordinates ourselves using the cubic-bezier option:

(0.25, 0.1), (0.25, 1)
(0.42, 0), (1, 1)
(0, 0), (0.58, 1)
(0.42, 0), (0.58, 1)
(0, 1), (1, 0)

The mechanics of Bézier curves are described in detail on Wikipedia as follows:

Four points P0, P1, P2 and P3 in the plane or in three-dimensional space define a cubic Bézier curve. The curve starts at P0 going toward P1 and arrives at P3 coming from the direction of P2.

There's a bit more to it than that of course as you can find out on that page, but what's important is that you see how the five graphics above match the movements of the five boxes in the previous section. The x-axis represents time and the y-axis the displacement (horizontal in this case).

Check out this great resource for generating your own custom Bézier curves online. Remember you're not limited to using anchor points inside the box.

The graphs above were generated using BezierText 1.0.1 (freeware) for OSX

Image Cross Fade

Here's an interesting use for CSS transitions - a dynamic fade from one photo to another. When you mouseover the photo of Hilary it will fade gracefully into a photo of Barak. Move the mouse away and the transition is repeated in reverse.

Here are the styles used for this effect (no JavaScript required):

<style> .fader img { transition: 1s ease-in-out; } img.swap1, div.fader:hover img.swap2 { opacity: 1.0; } .fader:hover img.swap1, img.swap2 { opacity: 0; } </style>

This needs to be confirmed, but it appears some browsers now support transitions applied to background images - handling the cross-fade automatically.

Timer using transition-delay

Here's another interesting effect - a progress bar that counts off 5 seconds in half-second intervals. To start the animation just hold your mouse over the line of boxes and wait.

10% 20% 30% 40% 50% 60% 70% 80% 90% 100%

Again, this is achieved using no JavaScript and very little CSS. It's a bit of a hack, but surprisingly effective. The trick is to assign a transition-delay to each box to make them fire in sequence:

<style> .fader2 td { background-color: red; transition-timing-function: cubic-bezier(1,0,1,0); transition-duration: 0.5s; } .fader2:hover td { background-color: green; } </style> <table class="fader2" cellpadding="10" cellspacing="2"> <tbody> <tr> <td style="transition-delay: 0s;">10%</td> <td style="transition-delay: 0.5s;">20%</td> <td style="transition-delay: 1.0s;">30%</td> <td style="transition-delay: 1.5s;">40%</td> <td style="transition-delay: 2.0s;">50%</td> <td style="transition-delay: 2.5s;">60%</td> <td style="transition-delay: 3.0s;">70%</td> <td style="transition-delay: 3.5s;">80%</td> <td style="transition-delay: 4.0s;">90%</td> <td style="transition-delay: 4.5s;">100%</td> </tr> </tbody> </table>

The cubic-bezier(1,0,1,0) represents a curve that starts out flat and then rises sharply at the end of the transition period. You could also achieve this effect using the steps timing funciton.

Thinking outside the box

As hinted at earlier, using Bézier points outside the standard range of (0,0) to (1,1) can produce some very interesting effects, especially for those interested in more realistice movement effects.


Note in particular the behaviour of the last two balloons. By using coordinates higher than 1.0 we've created an animation that overshoots the target and then returns. The final example overshoots the mark in both directions causing a bounce/settling effect.

Here is the relevant CSS for these transitions:

<style> .stable .balloon.bezier1 { transition-timing-function: cubic-bezier(0,1,0,1); } .stable .balloon.bezier2 { transition-timing-function: cubic-bezier(0,1,1,0); } .stable .balloon.bezier3 { transition-timing-function: cubic-bezier(1,0,1,0); } .stable .balloon.bezier4 { transition-timing-function: cubic-bezier(0,1.5,0.5,1); } .stable .balloon.bezier5 { transition-timing-function: cubic-bezier(0,2,1,0.5); } </style>

The only change between this and the first example is that we've used different transition timing functions. There are also cases where the animated elements can be made to start off moving in the wrong direction.

Stepping it up

A little known option for transition timing functions is the steps function. This replaces the smooth transitions with a series of distinct steps. You can control how many steps to use in the transition, and whether the action occurs at the start or at the end of each step.


In this example when you move your mouse over the box it will fill up from left to right with a red shade using steps(10, start), and from the bottom with a blue shade using steps(10, end). There are 10 steps spread over a 5 second interval so they occur every 0.5 seconds.

You will see the red shade appear immediately from the left and cover the entire width at the 4.5 second mark. The blue shade will appear after 0.5 seconds and fill the box at the 5 second mark. That is the only real difference between using 'start' and 'end'.

<style> .step-right { position: absolute; bottom: 0; left: 0; width: 0; height: 100%; background-color: rgba(255,0,0,0.5); } .stable:hover .step-right { width: 100%; transition-duration: 5s; transition-timing-function: steps(10, start); } .step-up { position: absolute; bottom: 0; left: 0; width: 100%; height: 0; background-color: rgba(0,0,255,0.5); } .stable:hover .step-up { height: 100%; transition-duration: 5s; transition-timing-function: steps(10, end); } </style> <div class="stable"> <div class="step-right"></div> <div class="step-up"></div> </div>

If you're using an old browser or mobile device then to get these examples working in WebKit add the -webkit- prefix and for Opera the -o- prefix. For Firefox the prefix is -moz-. Internet Explorer 9 and earlier do not support CSS3 transitions.

So what do you think? Is this the 'Flash killer' that we've been waiting for?


User Comments

Post your comment or question

7 September, 2023

dude! that was fantastic thank you

6 March, 2022

Gorgeous! But, I tried to activate the code and the balloons do not 'swing' right and left. Just go straight up. Something seems to be missing. No? Thanks!

Look in the page source code for 'wobble'

28 May, 2018

it was a good explanation of transition but there is still a doubt left in my mind. learned how to delay transition thanks to your explanation but what my problem is that i want reverse transition delay of 0s so that the transition could occur instantly when i remove cursor from div.

16 September, 2014

thanks for your tutorial. i have a question that is confusing me. what is the difference between animation-duration and animation-delay in css3. i have come across areas where both are used and i cant tell the difference. thanks in advance.

animation-delay is a pause before the animation starts while animation-duration is the duration from when the animation starts to when it ends.

7 September, 2011

Man I'm so proud I figured out how to make an automatic fade with well positionned images. It was originally working with the cycle plugin:

8 July, 2011

Hi. I really like these transition effects. I was testing the same thing for background-image instead of background color, but it's not working. I'd like to know your results for this.

Transitions only work on 'scalar' values. During the transition the value gradually changes from the original value to the target value, passing through points in between.

For a background-image there are no intermediate points so there won't be any transition.

30 June, 2011

I don't understand how tha last example works : each <td> works individually, but there is only one hover ?

Normally, all the <td> have to go green at the same time... Isn't it ?

The trick is that each box undergoes the same transition, and starting at the same time, but the durations are different. It also uses a cubic-bezier function that is very steep at the end of the transition.

19 March, 2011

In the Transition Timing Function Options example, all you have to do is hover over the body and all the boxes move. How do you do that?

The shaded area has an id value of "stable" and each box has a class of "showbox". The CSS to trigger the animation then is something like this:

#stable:hover .showbox {
-webkit-transform: translate(590px,0) rotate(5deg) skew(-15deg,0);

So when #stable experiences a ':hover' event, all the child boxes are translated and transformed. Each box also has it's own transition-timing-function assigned in the HTML.

12 March, 2011

I've recently upgraded firefox to the new 4.0 beta and all the transitions work great. Very nice examples by the way =)

16 February, 2011

Something seems to be missing from my understanding of the concept here. Do these examples all require JavaScript? How is the triggering event defined in these -- IE, where is the "hover" element coming from? Is this part of CSS3?

No, it's only CSS -just not supported by IE.

17 January, 2011


Is there any way to to that without the hover? I mean, the transition start without the rollover?

To have the animation start automatically (without JavaScript) you need to set up keyframes, as demonostrated in this article.

23 December, 2010

Hey, thanks for the examples of bezier curves as a way to calculate interpolations, i've been trying to make something similar without getting good results.
but with your examples it all went fine!
if you have more examples (like control points for the bezier curve) it'll be awesome!

14 December, 2010

@Gail Lang Firefox 4+ supports CSS3 transitions but not other versions

10 December, 2010

Wow, these examples are really cool!

Gotta wonder, though, is the lack of Microsoft support going to kill these awesome features, again? I just finally deprecated all IE6 support only to now have nothing in HTML5 supported by MS, yet... Any idea whether they will?

And if they will, will they do it correctly?

There's only limited support for CSS3 and HTML5 in IE9 so it's going to be a couple of years at least

20 September, 2010

Nice work; great visual examples!

20 August, 2010

I'm using FireFox 3.6.8 and these transition examples didn't 'transition' at all, they just instantly changed, all of them. I would love to see how they work since I'm currently learning HTML5 & CSS3, is there anything I can do?

You just need to install Safari, Chrome or Opera.