The Definitive Guide to CSS Transitions

Justyn Hornor

Back in the golden days of the web, we had a little thing called Flash to help us make the web a dynamic, fun, interactive place. But, Flash is being used less and less. Of course, in certain environments it can still be put to amazing use, but in today’s web environment you need CSS to get the job done.

One of the easiest ways to give your site a near-instant facelift is to bring CSS3 transitions to the table (pun intended). As users interact with various elements on your page, transitions allow for a delayed response that is far more natural and engaging than a jarring, instant response. Case in point, hover over these two boxes and tell me which is more interesting to you.

Drop this into an HTML document and check it out:


<html>
<head>

<style>
#box-static {width:250px; height:170px; background-color:#999; background-color:#999; float:left; margin:10px;}
#box-static:hover {background-color:#333;}
#box-dynamic {width:250px; height:170px; background-color:#999; background-color:#999; float:left; margin:10px; transition:all 1s;}
#box-dynamic:hover {background-color:#333;}

</style>

</head>
<body>

<div id="box-container" style="width:600px;height:200px;display:block;">

<div id="box-static"></div><div id="box-dynamic"></div>
</div>

</body>
</html>

Yeah, I know gray boxes aren’t all that exciting, but the point is that the transitions on the box to the right are more interesting and give the design a more polished feel.

Pseudo-Classes for CSS Transitions

The key to making CSS transitions work is through the use of pseudo-classes. You’ve seen these before, even if you didn’t know what they were called. The most common example is probably the a:hover pseudo-class.


a {
color:#CCC;
background-color:#333;
}

a:hover {
color:#333;
background-color:#CCC;
}

Here we have the CSS element for a link and the pseudo-class “hover” for when the mouse is over the link. Pseudo-classes are subsets of a class. They take on the parent CSS automagically and apply new or different CSS upon interacting.

Some other important pseudo-classes you need to know for CSS transitions include:

  • hover: obviously.
  • active: when an element gets clicked
  • focus: for tab-based selection (accessibility and forms)
  • target: for matching an on-page ID with a link target

I won’t address the target pseudo-class in this article because it’s rare and is still buggy across browsers. But hover, active, and focus are fully functional (IE10+) and easy to implement.

Introducing CSS Transitions

With all that background out of the way, we can have a more thorough discussion of CSS transitions. They are simply a CSS property that allows you to make the differences between two different CSS elements to change slowly instead of instantly. When you hover your mouse over a button that has a pseudo-class of hover with different color of text and background, the button immediately changes. Transitions allow you to make the change occur more slowly, giving your designs a far more interactive feel.

You can use transitions on just about any CSS element using pseudo-classes: divs, paragraphs, spans, tables and sub-elements of tables, images. Just apply the appropriate pseudo-class and define the CSS change. I stick with background-color for the most part as it creates an interesting effect.

Properties of the CSS Transition

To be thorough, the above example is simply consolidating several CSS Transition properties:

  • Transition-property: the CSS you want to target for the transition, like color, background-color, width, height, etc
  • Transition-duration: how long in seconds or milliseconds you want the transition to take.
    • For seconds, use an ‘s’ like 2s
    • for milliseconds, use ‘ms’ like 2000ms
  • Transition-timing-function: how the transition merges, meaning that you can adjust to have an eased transition, stepped, or linear. Default is ease, which works for 99% of what I need, but here are the primary attributes:
    • ease-in starts the transition slowly and finishes at full speed
    • ease-out starts the transition at full speedand finishes slowly
    • ease-in-out starts slowly, gets fastest in the middle of the transition, and finishes slowly.
    • ease is nearly identical to ease-in-out except it’s a little less dramatic towards the middle of the transition
  • Transition-delay: also in seconds or milliseconds, defines an amount of time to delay before starting the transition.

Or, you can consolidate all these into a single transition, just keep them in the following order:


transition: property duration timing-function delay;

A complete example would look like this:


a {
color:#CCC;
background-color:#333;
transition:color 1s ease-in-out 500ms, background-color 1s ease-in-out 500ms;
-webkit-transition:color 1s ease-in-out 500ms, background-color 1s ease-in-out 500ms;
}

a:hover {
color:#333;
background-color:#CCC;
}

Notice that you will need to use -webkit-transition to make these work in the vast majority of browsers.

In pseudo-code, this would read something like: transition the color of the link, make the transition take 1 second to complete, gently ease in and out of the transition, and delay for half a second (500ms) before making the transition.

You can use a comma-delimited list with the transition to cover all the target properties you want. I prefer to consolidate my transitions into the single CSS attribute, but if you had some very specific transitions you wanted to craft, you may want to break each down.

Where to Place Transitions

I wondered for awhile if I should place the transition in the parent or the child. After all, the following two examples have the same exact effect:


a {
color:#CCC;
background-color:#333;
transition:color 1s ease-in-out 500ms, background-color 1s ease-in-out 500ms;
-webkit-transition:color 1s ease-in-out 500ms, background-color 1s ease-in-out 500ms;
}

a:hover {
color:#333;
background-color:#CCC;
}

–OR–


a {
color:#CCC;
background-color:#333;
}

a:hover {
color:#333;
background-color:#CCC;
transition:color 1s ease-in-out 500ms, background-color 1s ease-in-out 500ms;
-webkit-transition:color 1s ease-in-out 500ms, background-color 1s ease-in-out 500ms;
}

But here’s what I’ve found, I prefer to put the transition in the parent so that all other child elements get the transition. If you want separate effects based upon the situation, you can always provide a different transition specific to that element. But I find that to be extremely rare. 99% of the time I want a consistent transition effect, so I put the transition in the parent element.

Beyond :hover and Links

Two other really important pseudo-classes need to be discussed for this to be a thorough guide: active and focus.

Active is when an items is actually clicked and can have its own separate transitions. While not critical from a design standpoint, this can add a whole other layer of interactivity to your designs.

Focus is for tab-based browsing. I use it on forms and navigation elements primarily, but should be considered any time you need to make your site more accessible.

My focus typically mirrors my hover, simply because they’re about the same thing from a functionality standpoint. This is where delaying the effect by 250-500 milliseconds can be useful so that you users aren’t tabbing through what may look like a Christmas tree as every tabbed element goes through a transition.

Working Sample

Let’s pull all these concepts together into a complete working sample. I like using transitions on menu items:

<html>
<head>
<style>

/* make the li inline for horizontal menu */
#menu li {
display:inline;
font-size:18px;
margin: 3px 8px 3px 8px;
}
/* initial definitions */
#menu a {
color:#333;
border-bottom: #333 2px solid;
background-color:#fff;
padding:5px;
text-decoration:none;
transition:color 1s ease-out 250ms, background-color 1s ease-out 250ms;
-webkit-transition:color 1s ease-out 250ms, background-color 1s ease-out 250ms;
}

#menu a:hover {
color:#fff;
background-color:#666;
}

#menu a:focus {
color:#fff;
background-color:#666;
}

/* note how I made the transition delay 0ms */
#menu a:active {
color:#333;
background-color:#666;
transition: 1s 0ms;
}

</style>

</head>

<body>
<div id="menu">
<ul>
<li><a href="#" tabindex="1">Nav Text 1</a></li>
<li><a href="#" tabindex="2">Nav Text 2</a></li>
<li><a href="#" tabindex="3">Nav Text 3</a></li>
<li><a href="#" tabindex="4">Nav Text 4</a></li>
<li><a href="#" tabindex="5">Nav Text 5</a></li>
</ul>
</div>
</body>
</html>

Do you rely on CSS3 transitions within your designs?. Would you use it for essential functionality, or just an added layer of polish for those who support it with modern browsers?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://georgelangley.ca George Langley

    I can see using them as a tasty addition, but I wouldn’t put any delays on them – makes it sloppy and confusing to the user.

  • RidleyO

    Any demo links? I like to see the demo so I know if I want to read the article.

  • http://www.digiflip.tv Mark Law

    Great post Justyn! It would be awesome if you could add these and other examples to http://codepen.io/

    That way we can play instantly ;)

  • http://holidaymull.co.uk Tim Dawson

    In your final example the menu items appear to retain focus after clicking and moving the mouse away. I have copied your CSS (for the :hover, :focus and :active states), but I can only get focus by tabbing. With the mouse I get the :hover state, and briefly the :active (while clicking), but never :focus. I’m wondering if I’ve missed something, or if my other CSS could be negating :focus. Browser is Firefox21.