A few years back, I saw a great episode of Mythbusters, where they tested the idea of the Chinese water torture. One by one, Adam, Kari, Scotty and Tory were each firmly secured before being subjected to the slow, rhythmic beat of droplets onto their foreheads.
And one by one, each was broken down — in Kari’s case, to the point of tears — in under an hour.
It’s not the most comfortable thing to watch, but it offers an obvious take-away: While some rhythms can be soothing, tight repetition can quickly drive us stark-raving mad.
Of course, as web people, we already know this intuitively!
Who hasn’t experienced the site with the endlessly spinning logo? Who hasn’t been driven to distraction by that industrious little construction worker toiling away behind an “Under Construction” sign?
It raises an obvious question: Is it possible to use animation without introducing these mind-torturing loops?
Let’s see what we can do.
To keep things breezy to read, I’m going to use the official “unprefixed” W3C syntax (i.e. @keyframe) throughout this article, but you’ll need to use the browser-specific prefixes (i.e. @-webkit-keyframe, @-moz-keyframe, @-ms-keyframe, etc.) to see it working in real-world browsers.
The core concept behind CSS3 animation is to let you transition between CSS properties. Like all animation, CSS3 needs a timeline with a start and a finish — set at 0% and 100% respectively. The code for the simplest of animation timelines would look like this:
Here’s how to include a time length within your CSS:
We’re free to create as many points along the timeline as we’d like — for instance we can change our animation to green (#0f0) at the halfway point by adding the following line:
Working with CSS3 SpritesNote: For all the demos in this article, I’m going to be using Lea Verou’s super-lovely Dabblet webapp. Apart from looking luscious and being hard-wired straight into Github, Dabblet will let you fiddle with the CSS here and see the results in real-time. The other great feature of Dabblet is that it let’s you write plain, unprefixed CSS3 while magically adding the browser-specific code in the background (using Lea’s “–prefix-free”).
This is brilliant for keeping the code examples simple to read, but be aware that you’ll need to add the “-moz,” “-webkit,” and “-ms” prefixes to make this code work outside of Dabblet.
So, despite only really having one good trick — transitioning between CSS properties along a timeline — CSS3 keyframes give you many of the basic building blocks of animation including:
- Squash and stretch (in CSS: width, height)
- Rotation (transform:rotate)
- Position in space (left, right, top & bottom)
- Color and opacity changes (color, background-color, opacity)
However, it’s not so obvious how you would, for instance, manipulate CSS properties to make:
- a wriggling snake
- flapping wings
- a spinning earth
- a running man
So, how do we do that with CSS3?
Let’s begin with a simple cel animation that we can develop into something more sophisticated. I’m starting with single .png showing a hand-drawn flame over three frames. It won’t be hard to make this image loop seamlessly.
Each flame cel is 136px high by 100px wide.
The SetupHere’s the basic HTML framework that I’m starting with:
(#logfire) to hold the background graphic and a placeholder
(#flamegroup) that will hold our flames in position. Inside the placeholder I’ve nested a third
(.flame) that will become our flame.
I’ve embedded the flame graphic into the background-image, but we’re cropping off most of the image, only allowing the left-hand flame to show.
Setting Up Our TimelineTo make a seamless loop, we’ll need to create a 4-frame loop — that is, we’ll show frames 1,2,3, and 2 again, and repeat. We could represent that sequence along our invisible timeline as positions 0%, 25%, 50%, 75% and 100% (i.e. back to frame 1). At each stage we reposition our background at the next frame, so our CSS might look something like this:
As the above example shows, it animates too nicely, gracefully sliding between frames. Just like those little page-flick animations you used to make in the corners of book pages, the magic lies in snapping each new frame into place so quickly that you can’t see the in-between state.
Our new jagged timeline now looks like this:
I think you get the idea.
If we plug that CSS into our example we now get a pleasantly wiggling flame.
Add a PulseFlames don’t just move, they vary mildly in intensity. Since we already have the timeline set up, why not tweak the opacity a little to give it a subtle pulse?
A decent result, but let’s face it: We could get something pretty close to this with a good animated .gif file. Let’s ratchet things up a little.
Fan those FlamesCircling back to our original HTML, we’re going to add more flame elements — lucky we have that handy holder
Let’s add two more
elements with the “flame” class to our “flamegroup.” We’ll also give each
it’s own ID so we can target them separately.
Finally, rather than stacking them precisely on top of each other, I’m going to offset each flame slightly (10-20px) from its siblings. This is mainly so we can see the edges mingle and interact.
Here’s the CSS:
Our flames jump, dance and weave in a soft, less “GIF-loopy” manner. Sometimes you think you have the pattern nailed but then it seems to shift. Dabblet lets you tinker, so feel free to play with the timing. Obviously the slower the loop, the longer between exact pattern repeats.
There are a few points to be aware of:
- As I mentioned earlier, the Dabblet examples use “–prefix-free” to let us write clean, unprefixed CSS3, but you’ll need to add the “-moz,” “-webkit,” and “-ms” prefixes to make this code work outside of Dabblet.
- I wanted to keep things relatively simple for the example, but we
could easily spice things up a little more by setting background-size
height to 100%, and then animating the height of our flame . This would make our flames leap and dive more energetically.
- Obviously, older browsers won’t support CSS3 animation, but Modernizr.com allows you to target those browsers with a fallback. For older browsers, rendering the flames statically seems to be a perfectly acceptable option. In fact, it’s hard to imagine how an IE8 user would ever become aware that other users were seeing an animation.
- You may sometimes see a slight “jog” or flicker randomly in the animation. It seems to be a browser buffer overflow bug, but so far I haven’t found a way to eliminate it, although slower computers seem to make it worse.
Summing Up…I think this idea of weaving together animation timings has some interesting potential, so watch this space in the coming weeks for some more experiments. Subtle sunlight, water, and clouds effects come to mind.
So, what do you think?
And if you have any ideas of your own, make a Dabblet and share them here.
UPDATE: March 1st, 2012
Reading up on the CSS animation spec, I’ve found there’s a better way to control the sprite switching. The @keyframe syntax has a reasonably rarely-used attribute called ‘step’ that allows you to control how many ‘inbetween’ animation states are generated by the browser. It looks like this in it’s unprefixed state:
Playing with Fire: Organic CSS3 Animation Reviewed by Aamir Pathan on 12:26 PM Rating: