A masterclass in CSS animations

From the basics of animation keyframes to expert animation tips that will save you many a headache, Estelle Weyl, web developer and author of HTML5 and CSS3 For the Real World, takes you on a tour of all you need to know to get up and running with CSS3 animations

Shares

"Animating" with CSS used to be limited to hovering effects. With :hover and :focus pseudo classes we've been able to change color, size, background-color, position, and many other CSS properties based on user action. The :hover trick provides only two states - hovered and non-hovered - with only two keyframes: start and end, and no tweening between these states, creating a harsh and sudden transition. This isn't really animation.

CSS3 transitions solved the tweening issue, enabling transitioning from non-hovered to hovered style (and back) over a period of time. Vendor-prefixed transitions are well supported in modern browsers (starting with IE10 and Firefox 4.0). With transitions, we can create limited simple animations with two keyframes - a start and finish point - and to a single iteration. Most developers have been overcoming these limitations by using JavaScript to animate. With increased support of CSS3 animations, it's time to rely less on JavaScript and animate natively with CSS.

In this article you'll learn what you need to know to get started with CSS3 animations. Note that animations are currently supported, prefixed with -webkit- and -moz-, in Chrome, Safari 4+, Firefox 5+, Android Chrome, and iOS webkit.

Keyframes

To animate elements you first need to define a keyframe animation. Then you apply that animation to the elements you want to animate. The first step is to define your animation, which you can attach to an infinite number of elements. Animations are similar to transitions except they provide for more granular control. The minimum required to define an animation is an animation name, a starting point or keyframe and an ending point or keyframe.

Don't forget the %When it comes to lengths, like px and ems, 0 is 0. Note in animation declarations. Don't forget the % unit of measurement.

Don't forget the 100%, or final to keyframe declarationWhile the 0% and 100% are not required by the specifications, they need to be included for current browser implementations.

Don't quote the animation nameAlthough quoting the animation provides for more legible markup, adding quotes to the name in incorrect according to W3C draft specifications, and will make the animation fail in Firefox.

One of the features that makes keyframe animation more powerful than transitions is the ability to control the animation on a granular level. For example, the rainbow animation below has 11 keyframe blocks:

Had we used CSS transitions to go from #FF0000 to #FF0080, we would have transitioned from red to magenta, showing only colours in the red spectrum. With animation keyframe granular control, our animation goes from red to pink by going through the colour spectrum.

We can include as many animatable properties as we want to animate in any keyframe block. See the example here.

In this example, opacity will change from opaque to transparent and back opaque, while the colour will go through the spectrum. Note that we didn't need to declare every property in every keyframe block. Rather, we only included properties when that property needed a keyframe definition.

Note that duplicate keyframe selectors are not supported:

100% {background-color: #FF0080;}

100% {opacity: 1;}

When two keyframe blocks have the same selector, as per the cascade, the last block overrides previously declared blocks. Had we written the above, line 9 would be ignored, overridden by line 10, which has the same keyframe selector value.

On the other hand, if you have an animation that has duplicate keyframes, you don't have to declare the same block twice. Instead, separate the selectors of the duplicate keyframes with a comma. Note that the order of the declarations doesn't matter (100% can come before 0%). In the butterfly example, we want to start and end our butterfly movement animation with the butterfly in the exact same location. Instead of declaring two separate code blocks, we simply separate the first and last keyframe selectors with a comma:

We declare three of the four 'bottom' keyframes together, since the final keyframe includes more than one property. You can only use comma-separated duplicate keyframes when all the property/values in the keyframe block are the same.

Note that we had two properties being animated. We moved the ball up and down numerous times with granular control. The left to right motion, however, was smooth, and therefore only needed two keyframe declarations. We've also changed the animation timing function to make the bounce look smooth and natural. We'll discuss the animation timing function part of this animation below, but the important thing to note is that the animation-timing-function is the only animation property that can be included within keyframe declarations. The W3C has an incomplete list of properties that are animatable. We can include the animation timing function to define how the animation moves to the next keyframe. Without it, our bouncing ball animation above was very jumpy.

Vendor prefixing

Our animations above won't actually work anywhere. At the time of this writing, the only browsers that support animations require vendor prefixes. We have to declare the @keyframes three times: with -moz- for Firefox 5+, with the -webkit- prefix for Safari, Chrome and the various mobile webkit browsers and last, without any prefixes, for when browsers support the vendor-neutral syntax.

In this example, we've added the vendor prefixing in front of the 'keyframes' keyword, and also for the transform property, as vendor-less transforms are not yet supported.

Animating Elements

Now that we have animations declared, we can animate elements on our page by attaching animations to them. We need to at least provide the element with the animation name and duration. There are many other properties that enable us to control the appearance of animations, but the name and duration are required.

Animation-name and animation-duration

Our first goal is to make the butterfly flitter. To apply an animation we provide the element with the name of the animation to use AND the duration of that animation. For that we have two properties: animation-name and animation-duration. The animation-name property accepts a comma separated list of unquoted animation names. These are the user defined names you defined in your @keyframes rule. So far in the examples above, we can include flapping, flitter, rainbow, rainbowdimmer and bouncing.

In addition to adding the animation name(s), we have to define how long the animations should last in seconds(s) or milliseconds (ms). Add the length of time it takes for the animation to iterate once from 0% to 100% with the animation-duration property. The minimum duration is 1ms. In our flapping example, we have been using 500ms, or 0.5s, in the above examples.

‘animation-iteration-count’

Our butterfly isn't flitting (or fluttering?). By default, animations only iterate through once. To make it flit several times, or forever, we can add the 'animation-iteration-count' property. The value of which is either an integer or the key term ‘infinite’. The default value is ‘1’.

animation-direction

The animation above is annoying not just because it won't stop, but because the animation goes from 0% keyframe to 100% over 500ms, but then jumps back to 0%. It scales over time from 100px wide to 20px wide, then jumps back to 100px as it starts its next iteration. The default process is for an animation to iterate from 0% to 100% over time, then to jump back to 0% to start the next iteration.

Sometimes you want animations to behave like transitions: when you transition on hover, the animation reverses on mouse out. With the animation-direction property, every other animation can be set to go from 100% to 0%. While a bouncing ball goes only in one direction, always going from 0% to 100%, the flitting of a butterfly is a good example of the need for alternating the direction of the animation. Let's add it to our butterfly:

‘animation-timing-function’

We can fine-tune our animation further by setting animation timing functions to control how these intermediate values are computed over time. The default value is 'ease' but most animal motions really ease in and out over time. We add the ease-in-out value to our animation timing function.

We've also added ease-in and ease-out at different steps in our bounce animation. The animation-timing-function is the only animation property that can be included within keyframe declarations. Include the animation timing function to define how the animation moves to the next keyframe. Without it, our bouncing ball animation above would have been very jumpy.

‘animation-delay’

By default, animation begin immediately when applied. We can control this with the animation delay property. While this is a simple to understand property, there is a cool trick to know about animation-delay. If you want an animation to begin halfway through the animation, include an animation-delay-value that is negative. For example, if you have a 10s animation, including an animation-delay: -5s; will cause the animation to start immediately, starting half way through the animation.

‘animation’ (shorthand)

Animation properties are verbose. Too verbose. Especially with vendor prefixing. Fortunately, there is a shorthand. The shorthand must include the name and duration of the animation. If you are including a delay, make sure the duration comes first! The order is generally:

Always consider the duration and interaction counts of the animations to time your animations well. Also consider what properties are being animated. While we can apply as many animations as we want to an element, we can only apply a single occurrence of a property at a time. In other words, while we may have four animations that we want to attach to an element, we can only apply one transform and one top/left position value at a time.

We added transform-origin to make the rotation appear more random and natural. Also note that we have three animations ending at 13, 11 and 13 seconds respectively. When including multiple animations, consider their timing relative to each other.

The animation-fill-mode takes one of four values: backwards, forwards, none or both, with default being none. The value of backwards makes the element go directly to keyframe 0% when the page loads, even if there is an animation-delay, staying there until the animation starts.

The value of forwards tells the browser to stop the animation on the last keyframe at the end of the last iteration and not revert back to its pre-animation state.

The value of both applies both backwards and forwards, sitting on the first keyframe until the animation begins (no matter the length of the positive animation delay) and staying on the last keyframe at the end of the last animation. This is what we want for our bounce:

Pausing and playing animations

In addition to pausing on the first and last keyframes with animation-fill-mode, we can pause along the way with the animation-play-state. By default, all animations are 'running', but they can be paused:

To see this hover declaration in action, simply hover over any animating butterfly above.

We've walked through a very simple animation. This is just to show what is possible. CSS animations are very powerful, providing a way of animating without the use of JavaScript, while providing event handlers should JavaScript events be necessary.

It is important to remember that just because animation is possible, does not mean that it is always a good idea. Use animation judiciously. We don't want to return to the animated gif state of the late 1990s, or the abundance of Flash intros look of the early 2000s.