Thomas Fuchs
Hi, I'm Thomas Fuchs. I'm the author of Zepto.js, of script.aculo.us, and I'm a Ruby on Rails core alumnus. With Amy Hoy I'm building cheerful software, like Freckle Time Tracking and Every Time Zone and write books like Retinafy.me.
   Want me to speak at your conference? Contact me!

Creating awesome CSS3 animations

August 27th, 2010

Yarrrr!! Meet Captain Track, the awesome animated CSS3 pirate!

First, grab a WebKit-based browser, like Safari (preferably, because it supports hardware-acceleration!) or Google Chrome and head over to timebemoney.com and say “yarrrr!” to Captain Track!

Note that on the iPad and iPhone, these animations run with a full, super-smooth 60 frames per second, because of all the hardware-accelerated glory in Mobile Safari.

The best thing is that all this glory will eventually come to all browsers, so don’t get left behind and start using this awesomeness now.

Here’s the whole animation dissected:

Arm & Map

The arm & map image is a transparent 24-bit PNG (note the translucent brownish shadow).

This image is absolutely positioned, and rotated around a point on the left border of the image, a bit down from the center, so it appears that the arm is rotated around the elbow of Captain Track.

@-webkit-keyframes arm {
  from { -webkit-transform: rotate(0deg); }
  70% { -webkit-transform: rotate(9.7deg); }
  to { -webkit-transform: rotate(0deg); }
}

#arm {
  position:absolute;
  left:360px;
  bottom:0;
  width:246px;
  height:210px;
  background:url(img/arm.png);
 
  -webkit-transform-origin:0% 60%;
  -webkit-animation:arm 3.9s ease-in-out infinite alternate;
}

As far as special CSS3 animation tricksery goes, the -webkit-transform-origin property can be used to set the point around which to rotate in the animation.

The animation itself is defined through the use of the @-webkit-keyframes keyword. This defines an animation by providing several keyframe definitions, that specify which CSS properties should be applied at which points in time during the animation.

The magic happens through the -webkit-animation property that will take a keyframe definition with several options and then smoothly animate the frames between the keyframes, so that in this example with the rotating arm the rotation is smoothly interpolated from 0 degrees to 9.7 degrees.

The -webkit-animation property takes several arguments:

  • Name of the animation’s keyframes definition (“arm”)
  • Duration of the animation (3.9 seconds)
  • Easing setting (“ease-in-out”). This is set to ease in and out so it looks better with the “alternate” animation style, where the animation goes back and forth
  • Iteration count setting (“infinite”)
  • Direction setting (“alternate”) – the animation “rocks back and forth” between 0% and 100% of the keyframes definition

As for the specific values to use–please do experiment! The only way to get good-looking animations is to practice making them and trying to tweak settings all over the place. Of utmost importance is perhaps the duration of the animation, followed by tweaks to the keyframe timing. For example, I used a 70% keyframe so that the durations of moving the arm from 0% to 70% and from 70% to 100% differ slightly, which makes the the back-and-forth rocking more appealing (this works really great together with the “alternate” setting).

While rotating, part of the arm is masked out with a simple positioned DIV with a black background, so that only the map part of the image overlaps into the central white background area.

Clock handles

The clock face is animated by using two copies of the same clock handle image, layered on top of each other. Again, 24-bit transparent PNGs are used:

@-webkit-keyframes pointer {
  from { -webkit-transform: rotate(0deg) scaleY(1); }
  25% { -webkit-transform: rotate(-90deg) scaleY(0.9); }
  50% { -webkit-transform: rotate(-180deg) scaleY(1); }
  75% { -webkit-transform: rotate(-270deg) scaleY(0.8); }
  to { -webkit-transform: rotate(-360deg) scaleY(1); }
}

#pointer1 {
  position:absolute;
  left:257px;
  top:177px;
  width:9px;
  height:23px;
  background:url(img/pointer1.png);
 
  -webkit-transform-origin:5.5px 18px;
  -webkit-animation:pointer 4s linear infinite;
 
  -moz-transform-origin:5.5px 18px;
  -moz-transform:rotate(55deg);
  -o-transform-origin:5.5px 18px;
  -o-transform:rotate(55deg);
}

#pointer2 {
  position:absolute;
  left:257px;
  top:177px;
  width:9px;
  height:23px;
  background:url(img/pointer1.png);
 
  -webkit-transform-origin:5.5px 18px;
  -webkit-animation:pointer 9s linear infinite;
 
  -moz-transform-origin:5.5px 18px;
  -moz-transform:rotate(-45deg);
  -o-transform-origin:5.5px 18px;
  -o-transform:rotate(-45deg);
}

The interesting part here is that the clock face isn’t really a circle but an ellipse, so I’m scaling the handles down horizontally a tiny bit with scaleY so it all fits in there.

The -moz-transform and -o-transform properties will make the clock handles show up in nicer default positions on Firefox and Opera (hope those browsers will support CSS3 animations soon!).

Eye (blink!)

The Eye is perhaps the most surprising element of the animation because it’s actually using none of the amazing new features, but rather uses a buzzword of the mid-90s: animated GIFs. Yes, you read right. Animated GIFs are widely supported across browsers and a relatively easy to create with tools like Photoshop.

First, here’s the eye in all it’s glory. Just wait for a bit and you will see it blink very briefly!

To create this in Photoshop, just have two layers, one with the eye open, and one with the eye closed, and then use the “Animation” palette to create a timeline-based animation (the darker areas show when the layers are shown). Save with “Save for Web & Devices…” and you’re all done!

This can be used for more complex animations, like the “map path” that shows up further down on the page.

Yarrr! Don’t forget, Captain Track loves to help you free-lance more efficiently!

Want to know more? Learn even more at my HTML5 Mobile Pro Workshop (next one is on October 5, 2010).