Year round learning for product, design and engineering professionals

Let the Web move you – CSS3 Animations and Transitions

Get yourself along to John Allsopp and Pasquale D’Silva’s workshop at Web Directions South: Animating Your User Experiences.

A brief history on Animation of the Web

If you’ve been developing for, or even just using the web for more than about 15 years, you’ll likely remember a time when animated effects were the bomb. Animated GIFs adorned just about every page, spinning globes, little men with jack hammers, self-folding winged envelopes. And if you’re very unlucky, you’ll remember the explosion of blinking content on the web around 1995, as the blink element in the then dominant Netscape browser took hold of the imagination of designers everywhere (for killing off the non-standard blink element alone, the web standards movement deserves at the very least a Noble Peace Prize). And perhaps the single widest JavaScript use in its earliest days was for creating image rollovers, until CSS got into the act with the hover state. In short, animation has had a long, if checkered career on the web.

Then, for years, animation fell out of favour, but with the rise of JavaScript libraries, we’ve seen the re-emergence of animated interfaces.

CSS3 animation

In the last 2 or 3 years, CSS3 has got into the act, providing a reasonably straightforward declarative way of creating even quite sophisticated animations, where complex JavaScript had previously been required.

In this article we’ll take a look at two related ways CSS3 provides for creating animations and animated effects, CSS Transitions and CSS Animations. We’ll look at how to create them, browser support, some interesting gotchas, and yet again, I’ll introduce a tool, AnimatR, I’ve created to help you more easily, and quickly, create cross-browser CSS animations. But please use animations wisely, tastefully and sparingly – we’ve take nearly 15 years to recover from the “blink tag”. Let’s not wait until 2026 for our next opportunity to get animations on the web right.

The JavaScript controversy

First up, let’s address a now fading controversy. When CSS animations were first proposed and experimentally introduced in Webkit, (coming up on 4 years ago now), many prominent, thoughtful developers felt strongly that animations were rightfully the domain of JavaScript, not CSS. Among the strongest, and most articulate, of those critics was Jonathan Snook, who subsequently revisited his concerns, and changed his position. In short, the concern is that animation is a kind of behavior, considered the domain of JavaScript, not presentation, the domain of CSS. But the simplest way of understanding an animation is that it is the change of presentational aspects of an element (height, width, color, etc.) over time. In short, animations are presentation, even if prior to CSS3 Transitions and Animations, they could only be achieved via JavaScript.

We also increasingly have the benefit that CSS based animation is being hardware accelerated in browsers, making for smoother animations and transitions even on relatively low powered mobile devices.

Let’s begin with the simpler CSS Transitions, then continue with CSS Animations. Animations reuse many of the concepts, and even syntax of transitions, so what we learn about transitions we can apply with animations as well.

Transitions

In CSS3, there are two kinds of animated effects – transitions and animations, which work in very similar ways. You might even think of transitions as simple kinds of animations. Transitions are the animation from one set of an element’s CSS property values of to another set. At their simplest, that might be a smooth animation from a background-color of red to a background-color of green.

Animations enable multiple changes to the presentational properties of an element over time – for example a 2 second animation from background-color of red to green, then a 1 second transition back to red again, repeated indefinitely (we’ll see less boring, and more useful animation examples shortly).

First introduced in Webkit and now supported across all modern browsers, including IE10 developer previews, transitions allow us to animate the change in presentation between two states, that is two sets of CSS properties. At its simplest, a transition might be just a smooth change from one value of a property to another value, over a specified period of time – for example, the smooth change of height over 2 seconds. To create simple transitions, we use the transition-property property, with a space separated list of CSS properties to be animated, and the transition-duration property, to specify how long the animation should take.

Here’s a really simple example: let’s cross fade a background-color from red to blue in 2 seconds.

p {
	transition-property: background-color;
	transition-duration: 2s;
	background-color: red;
}

Which leaves one simple question to answer – how do we trigger the change, and so the animated transition? Well, here’s the deceptive simplicity of transitions – they take place any time the specified property (in this case background-color) changes. So, if the background-color changes because we have a different background-color specified for the hover or other state, or if we use JavaScript to change the background-color, then those changes in color will be animated! Let’s try it out. If we specify a different background-color when the paragraph is in a hover state, like so:

p:hover {
	background-color: blue;
}

Then any time you hover over a p element, the color will fade. Let’s see that in action below

In all modern browsers (except IE9) this background color should fade from red to blue when you hover over it

A little pro tip as we go along – make sure you put the transition properties (transition-property, transition-delay etc.) on the element in its normal, not hover state.

But what’s with the s unit for the transition-duration property? CSS has in fact had units of time since CSS2. Originally part of Aural Style Sheets, we can specify time in either seconds (s) or milliseconds (ms) – 1,000 milliseconds in a second. CSS3 Transitions and Animations reuse these units, which are also part of CSS3 of course.

So, hopefully the basic idea is clear – with transitions we tell a browser that when a certain property or set of properties change, the change should not be abrupt, but be animated over a certain time period. Now, you might have noticed in the transition above the text color changes too – but does so without an animation. That’s because we’ve only specified that the background-color have an animated transition, via transition-property. We can as mentioned specify multiple properties, by listing each in a comma separated list of property names like so:

transition-property: background-color, color;

If we want all of the transitions to take the same amount of time, we can specify a single transition-duration property value. But, if we want different properties to transition over different time periods, we do so by listing the time values in a comma separated list – with the time periods and properties in the same position in their respective lists. Here for instance, the color will transition over 1s, while the background-color will do so over 2s:

p {
	transition-property: background-color, color;
	transition-duration: 2s, 1s;
	background-color: red;
}

And here this is in action:

In all modern browsers (except IE9) this background color should fade from red to blue when you hover over it, over a 2 second period, while the text color changes from black to green over 1 second.

If we want to animate the changes for any properties which change, we can use the keyword all as the value for transition-property. This will ensure that regardless of which property changes, that change will be animated (not all properties can in fact be animated – we’ll cover which ones can be shortly). Be careful with the all keyword – should future properties support animation, these will be animated, and it may not be clear at this stage just what these animations will look like.

There’s also the shorthand transition property which takes a space separated property name and time values like so:

p {
	transition: background-color 2s;
}

Note how there are no commas between the property and time value.

Or, if we have multiple property and time pairs, we separate each pair with a commas, like so

p {
	transition: background-color 2s, color 1s;
}

And in a nutshell, that’s the core of CSS3 transitions. We’ll touch on some gotchas (most of which are shared with animations) a little later. And we’ll take a look at browser support in detail in just a moment. But there are some optional features of transitions you might find useful, including specifying the nature of the transition, and a delay before a transition starts.

Transition Timing Functions

When a transition occurs, there are various ways the intermediate steps can take place. Let’s take the example of an element moving from left to right across the screen, over 2 seconds:

This element moves from left: 0% to left: 80% in 2s when you click it. It reverses this when you click it again.

Notice how it begins quickly, then slows down as the transition draws to an end. Now, take a look at the same transition below, with a very slight change.

This element moves from left: 0% to left: 80% in 2s when you when you click it. It reverses this when you click it again.

The difference between the two is they have different transition-timing-function properties. This property “describes how the intermediate values used during a transition will be calculated”. There are 5 timing function keywords (as well as some more complicated ways of describing timing functions mathematically using Bezier curves which we won’t go into here), ease, linear, ease-in, ease-out, ease-in-out.

Each of these is defined in mathematical terms in the specification, but it makes much more sense to let you see them all in action.

This transition has a timing function of ease, the default timing function. Click it to see it in action.
This transition has a timing function of linear. Click it to see it in action.
This transition has a timing function of ease-in. Click it to see it in action.
This transition has a timing function of ease-out. Click it to see it in action.
This transition has a timing function of ease-in-out. Click it to see it in action.

We specify an optional timing function (as noted above, the default is ease) using the property transition-timing-function, with one of the keywords above as its value. As mentioned, we can specify a timing function as a cubic Bezier curve, but if you need to get this technical with your transitions, the best place to understand the details is the specification.

Which timing function you choose is a matter of taste, and for most purposes, the default value of ease should be fine.

Delay

There may be occasions on which we want a transition to delay for a certain amount of time before commencing, and we can do this quite straightforwardly with the transition-delay property. As with transition-duration we do this using a time value in seconds or milliseconds.

transition-duration: 150ms;

We can also specify different delays for different transitions, like this (click the element below to see the effect):

This element transitions the change of top value, but delays the transition on the change of left value for .5s.
	transition-property: top, left;
	transition-duration: 2s, 1.5s;
	transition-delay: .5s, 0s;

Browser Support and Backwards Compatibility

So, having introduced such a mouthwatering prospect for designers, just how useable is it today? In fact, surprisingly so. All modern browsers support transitions, including IE10 developer previews. Firefox has done so since version 4, Safari since 3.2, Chrome since at least version 9, Opera since 10.6, iOS since 3.2 and Android since 2.1.

It does need to be noted that not all browsers animate all property changes – we’ll look at this in a little more detail in the animations section, since the list of properties applies to both animations and transitions.

However, as yet, all browsers require vendor prefixes in front of all the properties for transitions – which can make for some unwieldy CSS.

Since transitions only animate changes in style that are triggered either by a change in state (like hover or focus) or via JavaScript, they are effectively backwards compatible to just about any browsers likely to be used today. Users of those browsers simply don’t see the intermediate steps between one state and the other, merely the abrupt transition they’d always have seen. We just need to ensure that in the absence an animated transition, no information is lost.

From a usability and accessibility perspective, we should also be mindful that flashing content can trigger seizures in some users, and that sudden movements of content (for example a block of content from one place to another) in the absence of an animated transition may be disorienting, particularly for users with cognitive disabilities.

Transitions are straightforward to use, widely supported, backwards compatible, and can add a little more to your site or application. However just make sure you don’t overdo them. Remember the <blink>.

Animations

Similar in many ways to transitions, CSS Animations allow us to create multi-step animated content using only CSS and HTML (though we will often want to use just a little JavaScript to trigger the animation).

I’ve mentioned that animations and transitions have a good deal in common – here’s a quick look at their similarities and differences.

Similarities between CSS Transitions and Animations

  • Both animate the change in CSS property values over a period of time
  • Both have a duration
  • Both have an optional delay
  • Both have an optional timing function, defined in the same way

Differences between CSS Transitions and Animations

  • Animations can repeat any number of times
  • Animations can be specified to go in a forward and reverse direction
  • Animations can have any number of defined intermediate steps, called “keyframes”, but transitions only have a defined start and end “keyframes”.
  • With transitions we can specify an animation for any property which changes, using the all keyword. With animations, we need to specify every property we want animated.

How CSS Animations are defined

Creating a CSS3 animation is a little more work than creating a transition, involving two interlinked steps.

We need to create a regular CSS rule, which selects the element or elements we want to be animated, and we give this rule a set of CSS properties related to animations (we’ll look at these properties in a moment).

We also create an @keyframes rule, similar to an @media rule, which defines the two or more keyframes in our animation. If we have simply two keyframes, for the beginning and end of our animation, a transition is most likely the better choice. Each keyframe specifies the state of the animated properties at that particular time during the animation.

While it might sound a little complicated, each step is quite straightforward. Let’s take a look at each in turn.

The animation properties

Just as with transitions, we specify various aspects like the duration and timing function of the animation using CSS properties. But first we need to declare which @keyframes rule will be used to specify the keyframes of our animation, which we do using the animation-name property. Animation names follow the same rules as HTML4 id values – alphanumeric characters, dashes and underscores, and begin with a letter. Here we’re specifying that the header element should be animated using an @keyframes rule with the name opening-sequence (we’ll see very shortly how we give @keyframes rules names).

header {
	animation-name: opening-sequence;
}

Notice how the animation-name value is not quoted.

We’ll return to familiar territory by specifying a duration and timing function for the animation, using the properties animation-duration and animation-timing-function. As with transitions, the duration is specified in seconds or milliseconds, while the timing function takes one of the keywords we saw earlier (or again a more complex formula we’ll not go into here).

header {
	animation-name: opening-sequence;
	animation-duration: 5s;
	animation-timing-function: ease-in;
}

As with transitions, we can also delay the beginning of an animation, here using the animation-delay property, with a value once again in s or ms.

header {
	animation-delay: 500ms;
	animation-name: opening-sequence;
	animation-duration: 5s;
	animation-timing-function: ease-in;
}

So far, all should be very familiar from transitions. Now we meet two new properties. The first is for specifying how often the animation runs (once, a certain number of times, or indefinitely). The other is for specifying what happens when a repeating animation completes – should it begin again from its initial state, or play the animation in reverse? Let’s take a look at each.

Specifying that an animation should run more than once is very straightforward. We use the animation-iteration-count property, and give it either a numerical value, or the keyword infinite. The animation then runs the specified number of times, or indefinitely. The delay in commencing the animation only applies to the very beginning of the animation, and there will be no delay between iterations.

When an animation does run more than once, for example if an element moves from left to right on the page, what should happen when the next loop of the animation begins? There’s two possibilities. The animation could begin where it did the first time – for example on the left, as in this example

animation-direction: normal;

Or, the animation could reverse direction, returning to the starting values, as the animation below does:

animation-direction: alternate;

We define this behavior using the animation-direction property, which takes one of two possible keyword values: alternate or normal. To achieve the first of the effects above, we use the animation-direction property with a value of normal. The second of the two has a value of alternate for the animation-direction property.

Now we’ve set up part one of our animation, it’s time to create the animation itself. As we’ve mentioned, this is done using an @keyframes rule. The form of this rule is:

@keyframes opening-sequence {

  0% {
    /*properties to animate*/
  }

  20% {
    /*properties to animate*/
  }
  
  100% {
    /*properties to animate*/
  }
}

That is, we start with the keyword @keyframes. This is followed by the animation name. Next, inside curly braces (}"{" and "}") we have two or more keyframes. A keyframe has the form of a percentage value, and then a group of CSS properties inside their own curly braces.

The first keyframe must be 0%, and unlike elsewhere in CSS, the % is required. The last keyframe must be 100%. OK, so we can use the keyword from in place of 0% and to in place of 100%, but both the first and last keyframes must appear.

To create the animations above, we’d have this @keyframes rule:

@keyframes opening-sequence {

  0% {
left: 0%;
  }

  100% {
left: 80%;
  }
}

Note how our keyframes rule doesn’t have anything to say about the direction, duration, and so on. These are properties we specify for particular elements using the animation properties we’ve just seen. Both of the animations just above use the same @keyframes rule – they just have different animation-direction properties. Here are the complete rules for each of those animated elements

#normal-animation {
background: red;
position: relative;
width: 20%;
animation-name: opening-sequence;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: ease;
animation-direction: normal;
}
#alternate-animation {
background: red;
position: relative;
width: 20%;
animation-name: opening-sequence;
animation-duration: 5s;
animation-iteration-count: infinite;
animation-timing-function: ease;
animation-direction: alternate;
}

The only difference between the two is the value of the animation-direction property.

Let’s take a closer look at the @keyframes rule. Each keyframe is more or less like a regular CSS rule. In place of a selector like p.classname, it has a percentage value. The percentage value specifies where in the animation this keyframe belongs. For example a keyframe percentage of 40% in a 10 second animation occurs after 4 seconds.

It also has a declaration group of properties, separated by semicolons, as we’d find in a regular CSS rule. These define what the appearance of the selected element or elements should be at this point in the animation. The browser then animates the transitions between these keyframes.

Rather than go on in ever greater detail, perhaps the best way for you to get a better understanding of animations is to create some. And you don’t need to fire up a text editor, just head over to AnimatR, the tool I’ve developed to help you create animations. I’ll go into a bit more detail about how it works shortly, but it should make sense if you’ve read this far (and hopefully make more sense of what you have read).

Before and After Animation

Suppose we have this CSS

header {
	width: 90%;
	animation-name: opening-sequence;
	animation-delay: 2s;
	...
}

And this animation

@keyframes opening-sequence {
  0% {
    width: 40%;
  }
    
  100% {
    width: 60%;
  }
}

What width is the element during the 2 second delay before the animation begins? What about after the animation completes? In both cases, it’s 90% (which may not be what you want). But we can specify that instead of the applied properties, the opening and closing keyframe properties should apply during the animation delay, and after the animation completes using the animation-fill-mode property.

animation-fill-mode can take the following keyword values:

none
the default state, as described above
forwards
the properties from the 100% keyframe will continue to apply after the animation completes
backwards
the properties from the 0% keyframe apply during the delay period of the animation
both
both the forwards and backwards cases hold

Triggering animations

We saw that transitions occur when we change the associated CSS properties, either using CSS, or JavaScript. But when do animations occur? An animation will begin as soon as a page is loaded, which may not be what we want to occur. There’s various ways we can stop the animation auto-playing. We could not give an animation-name property to the elements we want to animate, and then apply this property using JavaScript when we want the animation to commence. But simpler in a way is to use the animation-play-state property. This takes one of two keywords, running or paused. We can change this using JavaScript:

element.style-animation-play-state="running";

Or even trigger an animation to run only when the user is hovering over an element (far from recommended):

header {
 animation-play-state: paused;
}

header:hover {
 animation-play-state: running;
}

Browser Support

We were in luck with transitions, as we saw they have widespread support in modern browsers, including IE10. We’re not quite so lucky with animations, but support is definitely on the increase. At present, Safari since version 4, Chrome since at least 9, Firefox since version 5, iOS since 3.2 and Android since 2.1 have support for animations. While support in Opera and Internet Explorer 10 has not been announced, as both these browsers support transitions, arguable the hardest part of CSS animations to implement, support for animation in these browsers may not be too far off.

As with transitions, all animation properties must currently have vendor prefixes: -webkit-, -moz- (and so on for future browser support). This is also true for @keyframes rules, but these have a slightly unusual format. Typically we prefix the property name, but for @keyframes the prefix comes after the @ and before the keyframes keyword, like so:

@-webkit-keyframes{
}

@-moz-keyframes {
}

As with transitions, animations will typically be backwards compatible, particularly if they are used to add a layer of enhanced user experience, rather than content in their own right. One area where animations are beginning to see some use is in browser-based games. As many browsers and devices hardware accelerate animations and transitions, for applications where performance is a significant issue, as it often is with games, animations will become an increasingly attractive solution. But here backwards compatibility is a significant issue – with games, animations aren’t simply decoration, they are central to the user experience. So, for some time to come, choosing to use CSS animation to develop games will necessarily mean excluding some users from playing those games.

Animations also pose a potentially significant challenge to creating accessible content. Where sophisticated animations are in essence an important part of the content, there is as yet no consensus as to how to make rich animations developed using CSS3 accessible.

Animation (and Transition) Gotchas

As a technology still in its infancy, animations do have a number of gotchas it is worth knowing about, to save hours of hair pulling and head-on-table banging. I’m sure there are many more than this, but here are some that I’ve come across.

Supported properties

Not all properties are animated. A list of properties that can be animated is outlined in the specification. Noteworthy is that background images can’t be animated (though properties like background-position are), with the theoretical exception of gradients (in practice gradients aren’t animated by any browser as yet).

It’s also important to note that transitions and animations only animate property transitions which would otherwise occur. For example

@keyframes widen {

  0% {
width: 5em;
  }

  100% {
width: 10em;
  }
}

won’t animate the width changes of an inline element like an <a>, because we can’t set an explicit width on an inline element. Similarly, for a paragraph which is statically positioned,

@keyframes move {

  0% {
left: 5em;
  }

  100% {
left: 10em;
  }
}

won’t animate the element, as we can’t set the position of elements with a position: static. So, if your animation or transition isn’t working, make sure the properties make sense. In the case of our link above, we could give it a display: inline-block, while in the case of the paragraph, a position: relative, and then the animations would take effect.

Animations in the Wild

So, just how sophisticated can CSS based animation be? Earlier this year, Naomi Atkinson and Mircea Piturca created an opening title sequence for our European conference, @media. Here’s a video of it appearing on the big screen, in front of hundreds of people in London’s famous Queen Elizabeth Hall:

Opening credits at Web Directions @media 2011 from Naomi Atkinson on Vimeo.

Renowned designer and developer Cameron Adams created these stunning opening titles for our conference, Web Directions South 2010. Displayed on two enormous screens in a theatre with a capacity of 1,000, it was an amazing sight to see. Note, this was expressly designed for 1024×768 resolution, and uses the font Gotham, so if possible, make sure you have the font, and set your screen to that size.

Perhaps the pre-eminent CSS Animator to date is Anthony Calzadilla, whose experiments and commercial work have really opened up people to what’s possible with CSS transitions and animations. Well known examples include Madmanimation, and an animated cover for the Wired Magazine iPad edition.

You’ll also find various collections of animation demonstrations like this one.

Introducing AnimatR

As CSS becomes ever more powerful and sophisticated, understanding, learning and remembering all the associated concepts, property names, syntax and so on becomes an ever more onerous job. So, as I am lazy, I’ve developed yet another tool, this time to help me (and hopefully you) understand and use CSS animations – AnimatR. AnimatR is not a WYSIWYG animation tool like Sencha’s slick Animator, the eagerly awaited Animatable, or the just announced Adobe Edge. Rather, it’s kind of like training wheels, to help you get up to speed with the concepts and syntax of animations (or for me a kind of Zimmer frame to help me totter along with all these new fangled CSS innovations).

It helps you easily set up the animation properties (except animation-play-state), as well as the keyframes for your animation. You can also add further style for the animated element, for example, giving it a position: absolute for animating an element’s location (an ever popular pastime).

To use the code you create with AnimatR, just change the #demo selector to select the element or elements you want to animate in your pages, and paste the contents of the code field into your style sheet. AnimatR will even generate the vendor prefixed versions for -moz- and -webkit- browsers (since Opera and IE have yet to announce support, I’ve not added support for these browsers yet).

Use wisely

Right now, there’s very little “hotter” in web development than animation, shown by the takeoff of Apple’s iAD, and other mobile advertising technologies along with tools like Adobe Edge and Sencha Animator. I hope you’ll agree they really aren’t all that complex to use, but also that they need to be used intelligently. The novelty of stuff on the web which flashes and moves has worn off (I hope). It’s time for web based animation that is smart and engaging. You have the tools – now get to it!

delivering year round learning for front end and full stack professionals

Learn more about us

Web Directions South is the must-attend event of the year for anyone serious about web development

Phil Whitehouse General Manager, DT Sydney