Open book with bookmark
Issue № 318 Illustration by

Understanding CSS3 Transitions

A note from the editors: We are pleased to present a portion of Chapter 2 of CSS3 for Web Designers by Dan Cederholm (A Book Apart, 2010).

It was 1997 and I was sitting in a terribly run-down apartment in beautiful Allston, Massachusetts. A typical late night of viewing source and teaching myself HTML followed a day of packing CDs at a local record label for peanuts (hence the run-down apartment). I’m sure you can relate.

Article Continues Below

One triumphant night, I pumped my fist in sweet victory. I’d just successfully coded my first JavaScript image rollover. Remember those?

I still remember the amazement of seeing a crudely designed button graphic I’d cobbled together “swap” to a different one when hovered over by the mouse. I barely had a clue as to what I was doing at the time, but making something on the page successfully change, dynamically, was, well…magical.

We’ve come a long way over the past decade in regard to interaction and visual experience on the web. Historically, technologies like Flash and JavaScript have enabled animation, movement, and interaction effects. But recently, with browsers rolling out support for CSS transitions and transforms, some of that animation and experience enrichment can now be comfortably moved to our stylesheets.

My first JavaScript rollover back in 1997 took me several nights of head scratching, many lines of code that seemed alien to me at the time, and multiple images. CSS3 today enables far richer, more flexible interactions through simple lines of code that thankfully degrade gracefully in the browsers that don’t yet support it.

We can start to use CSS3 transitions right now as long as we carefully choose the situations in which to use them. They certainly won’t replace existing technologies like Flash, JavaScript, or SVG (especially without broader browser support)—but they can be used to push the experience layer a notch higher. And most importantly, they’re relatively easy to implement for the web designer already familiar with CSS. It only takes a few lines of code.

Tail wagging the dog#section2

Initially developed solely by the WebKit team for Safari, CSS Transitions are now a Working Draft specification at the W3C. This is a nice example of browser innovation being folded back into a potential standard. I say potential since it’s merely a draft today. However, Opera has recently added CSS transitions support in version 10.5 and Firefox has pledged support for version 4.0. In other words, while it is a draft specification and evolving, it’s stable enough for Opera and Firefox to be taking it seriously and adding support for it. Most importantly, CSS transitions are no longer proprietary Safari-only experiments.

Let’s take a look at how transitions work, shall we?

What are CSS transitions?#section3

I like to think of CSS transitions like butter, smoothing out value changes in your stylesheets when triggered by interactions like hovering, clicking, and focusing. Unlike real butter, transitions aren’t fattening—they’re just a few simple rules in your stylesheet to enrich certain events in your designs.

The W3C explains CSS transitions quite simply:

CSS Transitions allow property changes in CSS values to occur smoothly over a specified duration. This smoothing animates the changing of a CSS value when triggered by a mouse click, focus or active state, or any changes to the element (including even a change on the element’s class attribute).

A simple example#section4

Here’s a simple example, where we’ll add a transition to the background color swap of a link. When hovered over, the link’s background color will change, and we’ll use a transition to smooth out that change—an effect previously only possible using Flash or JavaScript, but now possible with a few simple lines of CSS.

The markup is a simple hyperlink, like so:

<a href="#" class="foo">Transition me!</a>

Next, we’ll add a declaration for the normal link state with a little padding and a light green background, followed by the background swap to a darker green on hover:

a.foo {
  padding: 5px 10px;
  background: #9c3;
  }
a.foo:hover {
  background: #690;
  }
Normal and Hover Link Example

Figure 1: The normal and :hover state of the link.

Now let’s add a transition to that background color change. This will smooth out and animate the difference over a specified period of time.

Figure 2: Here we can see the smooth transition of light green to darker green background.

For the time being, we’ll use only the vendor-prefixed properties which currently work in WebKit-based browsers (Safari and Chrome) to keep things simple. Later, we’ll add vendor prefixes for Mozilla and Opera.

a.foo {
  padding: 5px 10px;
  background: #9c3;
  -webkit-transition-property: background;
  -webkit-transition-duration: 0.3s;
  -webkit-transition-timing-function: ease;
  }
a.foo:hover {
  background: #690;
  }

You’ll notice the three parts of a transition in the declaration:

  • transition-property: The property to be transitioned (in this case, the background property)
  • transition-duration: How long the transition should last (0.3 seconds)
  • transition-timing-function: How fast the transition happens over time (ease)

Timing functions (or, I really wish I’d paid attention in math class)#section5

The timing function value allows the speed of the transition to change over time by defining one of six possibilities: ease, linear, ease-in, ease-out, ease-in-out, and cubic-bezier (which allows you to define your own timing curve).

If you slept through geometry in high school like I did, don’t worry. I recommend simply plugging in each of these timing function values to see how they differ.

For our simple example, the duration of the transition is so quick (just a mere 0.3 seconds) that it’d be difficult to tell the difference between the six options. For longer animations, the timing function you choose becomes more of an important piece of the puzzle, as there’s time to notice the speed changes over the length of the animation.

When in doubt, ease (which is also the default value) or linear should work just fine for short transitions.

We could simplify the declaration significantly by using the transition shorthand property:

a.foo {
  padding: 5px 10px;
  background: #9c3;
  -webkit-transition: background 0.3s ease;
  }
a.foo:hover {
  background: #690;
  }

Now we have a much more compact rule that accomplishes the same result.

All of this wonderful transitioning works just fine in WebKit browsers, but what about the others?

Browser support#section6

As I mentioned earlier, transitions were initially developed by WebKit, and have been in Safari and Chrome since version 3.2, but Opera supports them as well in version 10.5 and support has been promised in Firefox 4.0. Because of that present and near-future support, it’s important to add the appropriate vendor prefixes so that our transitions will work in more browsers as support is rolled out.

Building the full transition stack#section7

Here’s a revised declaration, adding the -moz and -o prefixes as well as the actual CSS3 transition property. We’re putting the non-prefixed property last in the stack to ensure that the final implementation will trump the others as the property moves from draft to finished status.

a.foo {
  padding: 5px 10px;
  background: #9c3;
  -webkit-transition: background 0.3s ease;
  -moz-transition: background 0.3s ease;
  -o-transition: background 0.3s ease;
  transition: background 0.3s ease;
  }
a.foo:hover {
  background: #690;
  }

With that stack, we’ll be smoothing out that background color change in current versions of Safari, Chrome, and Opera, as well as future versions of any browser that chooses to support it.

Transitioning states#section8

I remember being slightly confused when I first started playing around with CSS Transitions. Wouldn’t it make more sense if the transition properties were placed in the :hover declaration, since that’s the trigger for the transition? The answer is that there are other possible states of an element besides :hover, and you’ll likely want that transition to happen on each of those without duplication.

For instance, you may want the transition to also happen on the :focus or :active pseudo-classes of the link as well. Instead of having to add the transition property stack to each of those declarations, the transition instructions are attached to the normal state and therefore declared only once.

The following example adds the same background switch to the :focus state. This enables triggering the transition from either hovering over or focusing the link (via the keyboard, for example).

a.foo {
  padding: 5px 10px;
  background: #9c3;
  -webkit-transition: background 0.3s ease;
  -moz-transition: background 0.3s ease;
  -o-transition: background 0.3s ease;
  transition: background 0.3s ease;
  }
a.foo:hover,
a.foo:focus {
  background: #690;
  }

Transitioning multiple properties#section9

Let’s say that along with the background color, we also want to change the link’s text color and transition that as well. We can do that by stringing multiple transitions together, separated by a comma. Each can have their varying duration and timing functions (Figure 3).

Figure 3: The normal and :hover states of the link.

a.foo {
  padding: 5px 10px;
  background: #9c3;
  -webkit-transition: background .3s ease,
    color 0.2s linear;
  -moz-transition: background .3s ease,
    color 0.2s linear;
  -o-transition: background .3s ease, color 0.2s linear;
  transition: background .3s ease, color 0.2s linear;
  }
a.foo:hover,
a.foo:focus {
  color: #030;
  background: #690;
  }

Transitioning all possible properties#section10

An alternative to listing multiple properties is using the all value. This will transition all available properties.

Let’s drop all into our simple example instead of listing background and color separately. They’ll now share the same duration and timing function.

a.foo {
  padding: 5px 10px;
  background: #9c3;
  -webkit-transition: all 0.3s ease;
  -moz-transition: all 0.3s ease;
  -o-transition: all 0.3s ease;
  transition: all 0.3s ease;
  }
a.foo:hover,
a.foo:focus {
  color: #030;
  background: #690;
  }

This is a convenient way of catching all the changes that happen on :hover, :focus, or :active events without having to list each property you’d like to transition.

Which CSS properties can be transitioned?#section11

Now that we’ve successfully transitioned the background and color of a hyperlink, there are many other CSS properties that can be transitioned, including width, opacity, position, and font-size. A chart of all the possible properties (and their types) that can be transitioned is available from the W3C.

Why not use JavaScript instead?#section12

You might be wondering, with not all browsers supporting (or at least promising support for) CSS Transitions, why not use a JavaScript solution to handle the animation? Popular frameworks such as jQuery, Prototype, and script.aculo.us have enabled animations via JavaScript that work cross-browser for some time now.

It all depends on how crucial the transitions are to the experience. I’m stressing here in this little book that you can embrace the simplicity and flexibility of CSS3 if you choose the appropriate parts of the user experience to apply it: enriching the interactions that happen on the page. Quite often, the animation of these interactions when handled by CSS Transitions aren’t integral to the brand, readability, or layout of the website. Therefore, a few simple lines of CSS to trigger a simple animation that’s native to the browsers that support it (rather than tapping into a JavaScript framework) seems like a smart choice. And one I’m glad we have at our disposal.

Be smart, be subtle#section13

Like all shiny new tools, it’s important to use transitions appropriately. One can easily go overboard adding transitions to everything on the page, resulting in some sort of annoying, pulsating monster. It’s key to decide where transitions rightfully enrich the user experience and when they are just extraneous noise. Additionally, making sure the speed of the transition doesn’t slow down an otherwise snappy action from the user is crucial. Use with care and caution.

About the Author

Dan Cederholm

Dan Cederholm is a designer, author, and speaker living in Salem, Massachusetts. He’s the Co-Founder of Dribbble, a community for designers, and Founder of SimpleBits, a tiny design studio. A long-time advocate of standards-based web design, Dan has worked with YouTube, Microsoft, Google, MTV, ESPN and others. He’s written several popular books about web design, and received a TechFellow award in early 2012. He’s currently an aspiring clawhammer banjoist and occasionally wears a baseball cap.

24 Reader Comments

  1. Loved the article. Did a great job of making transitions easier to understand. I ordered the book and can’t wait to get my grubby mitts on it.

  2. This was a really useful introduction. I think your point about browser support is a really good one – if something is essential then don’t use CSS3, but if it just subtly enhances the browsing experience then go for it.

    Another benefit of using CSS3 like this is that, over time, it will hopefully encourage less tech-savvy users to upgrade their browsers when they see how much better some sites work in modern, standards-compliant browsers.

  3. @Dan:Very nice and interesting article about CSS3 transitions. By the way it’s working pretty nice with Firefox 4.0b7.

    @Christophe: At the moment there excists no transitions support at the IE9b.

    All those CSS3 features like transitions, transforms and animations will be an interesting way to interact with the users, without flash.

  4. This CSS3 transition stuff looks interesting, but I find it a bit annoying how transition timing is specified. What happens if I want to animate the background property of an element on :hover and :active, but I want to use different timing for each? Say I want to have a softer transition for the :hover, but I want the :active to change near instantly? As it’s currently implemented, you can change the property value for different events, but the timing will all be the same. How can a situation like this be handled?

  5. It’s a nice introduction (though it could use a little word on how the inverted transition is supposed to work or could be changed to something different).

    What I’m really missing though is a fat warning against using these types of animations for functional animations. As properties like “height” can be adapted too it’s possible to hide content with no decent graceful fallback. You could argue that we’re all professionals and should know about that stuff already, but css3(/html5/new javascript) is drawing lots and lots of new people to the job which little prior understanding of the simple 3-way separation of content – style – function.

  6. Great peek at the new book, Dan—Can’t wait to get my copy. Congrats!

    Perhaps it’s covered later in the chapter, but combining CSS3 gradients with transitions doesn’t seem to work for me, though it seems to be listed as a supported property via background-image and I’m following spec… Any expert tips on making those happen?

  7. I recently tried to animate a sprite of 3 states and the animation was not smooth, actually a little jumpy beetween the state changes. Maybe I didn’t do it right or the transition between images is not done yet? I ended up doing it with jquery.

  8. Transitions on hovers are sweet and add that little extra to web designs. It’s a shame that IE still won’t add these features. Every client I’ve shown a site to in Chrome or Firefox that I’ve designed using transitions always wonder why it won’t show in their browser which is usually IE. Then you have to explain to them why it won’t work in IE which leads to the inevitable question about making it work in IE.

  9. Just wondering if there was a browser matrix for the compatibility of this demo. I understand that this article helps explains the theory, but as far as testing goes, I only got it working in OS X Chrome 7.0, but NOT in OS X Opera 10.63 (10.5 was mentioned as having support)

  10. This is the first time that I’ve looked at CSS3 Transitions, and luckily the demo was very well explained and the concept was kept simple. But having looked at the structure of how transitions are defined, I’m a little perplexed;

    Why do you give the transition property(s) to the element, and not the element :hover or the element :focus?

    Surely it makes more sense to be;

    a { color: black; }
    a:hover { -webkit-transition: color 3s ease; color: red; }

    Which would then enable you to specify other rules, like :focus, to use a different transition.

    Am I off the mark here, or does anyone share my opinion?

  11. Opera 11.0/Windows will not apply any transitions to an element, if the shorthand CSS is used.

    So this example will not work in Opera:

    -o-transition: background 0.3s ease;

    And this one will work:

    -o-transition: background-color 0.3s ease;

    (As far as I know, a bug was filed, hopefully one of the 11.x dot releases of Opera will have this fixed…)

    I think it would be good to mention this in the article, since many people perhaps tried the examples right away and may have found that they are not working in Opera. (I was trying to understand why the CSS3 transitions don’t work for quite a while, before a friend of mine mentioned to me this obscure shorthand bug…)

  12. @Gonzo:

    True, but Opera 10.6 (which is much older than version 11) shows the same bug as Opera 11.0 — as far as I am able to tell, at least, since I tested both on Opera 10.6 and 11.0. 🙂

  13. Thanks so much for this post. It was a really cool introduction to CSS3 transitions. This is actually the first tutorial article I’ve read about them. Really helpful thanks.

  14. For all interested, the article didn’t mention one of the chief use-cases for transitions – on devices such as the iPhone/iPad, they’re hardware-accelerated, and as a result much more efficient than using single-threaded Javascript to handle animation timing.

  15. Strange, i’m trying your example of the background transition and it doesn’t seem to work on Firefox 3.6.13 or Opera 11, only works on Chrome.

    a.foo {
    padding: 5px 10px;
    background: #9c3;
    -webkit-transition-property: background;
    -webkit-transition-duration: 0.5s;
    -webkit-transition-timing-function: ease;
    -moz-transition: background 0.3s ease;
    -o-transition: background 0.3s ease;
    transition: background 0.3s ease;
    }

  16. Agreed.
    Using Firefox 3.6.3. I am also unable to get the transition to work. Fails on IE v8.0 too.
    I made the duration 20 seconds in the hope of seeing some difference and -color to each of the attributes but still no go!?

    a.foo
    {
    padding: 5px 10px;
    background-color: #9c3;
    -webkit-transition: background-color 20.0s ease;
    -moz-transition: background-color 20.0s ease;
    -o-transition: background-color 20.0s ease;
    transition: background-color 20.0s ease;
    }

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career