Design Method

Let’s Cook Pixel Pancakes! A CSS3 Animation Tutorial


 

It’s that time of week again! Cue the epic music; it’s Tutorial Tuesday!

As it’s Pancake Day, I thought it would be a good idea to use this for inspiration for today’s post. We will in fact be cooking some pancakes with our lovely pixelated friend, Bob.

Try hovering over him to take a look at the end result:

Pancake
Bob's arm
Bob's cooker
Fire
Bob
Bob's head

Doesn’t he look ecstatic? The animation above is achieved using a combination of HTML, CSS3 and images.

Before we proceed, I’d like to clarify that the purpose of this tutorial is to showcase what can be done via CSS3 animations. I won’t be creating JavaScript fallbacks; browsers that don’t support CSS3 animations will just see a static version of Bob (with the exception of the flame, which is animated by using a .gif file).

In addition, please note that I won’t be using vendor prefixes to keep things concise. Here’s an article on CSS Tricks in case you need help setting up vendor prefixes.

The HTML & CSS

Let’s start by preparing the images. Bob and his cooker are actually comprised of 6 layers stacked on top of each other as shown below:

Bob - Blueprint

The order in which they’re stacked on top of each other doesn’t generally matter, with the exception of the pancake and arm. These need to be placed behind the rest of the images by either defining z-index values, or by utilising the natural stacking order; you’ll see the reason for this later. Personally I opted to use the natural stacking order as it’ll help me cut out a few lines of CSS. It’s also worth noting that I used an animated .gif for the flame.

Here’s the snippet of HTML I used:

[html]
<div id="animation">
<img id="pancake" alt="Pancake" src="images/pancake.gif" width="27" height="9" />
<img id="arm" alt="Bob’s arm" src="images/arm.gif" width="105" height="45" />
<img id="cooker" alt="Cooker" src="images/cooker.gif" width="93" height="177" />
<img id="fire" alt="Fire" src="images/fire.gif" width="21" height="21" />
<img id="bob" alt="Bob" src="images/bob.gif" width="78" height="231" />
<img id="head" alt="Bob’s head" src="images/head.gif" width="48" height="75" />
</div>
[/html]

The above just consists of 6 images placed within a container <div>. Let’s add some CSS to make the images appear as they should.

[css]
#animation {
padding-top: 20px;
width: 205px;
height: 303px;
position: relative;
}
#animation img {
position: absolute;
top: 20px;
left: 0;
}
#animation #head {
left: 15px;
}
#animation #bob {
top: 92px;
}
#animation #arm {
top: 122px;
left: 63px;
}
#animation #cooker {
top: 146px;
left: 112px;
}
#animation #pancake {
top: 152px;
left: 135px;
}
#animation #fire {
top: 167px;
left: 136px;
}
[/css]

There’s 4 things I’ve done in the CSS above:

  1. I set the container to position: relative; so that I could position the child images in relation to the container, i.e. div#animation.
  2. I set the position of each image using position: absolute;.
  3. I explicitly set the width and height of the container. This is required as the container would otherwise have no dimensions due to the fact that all it’s child elements are positioned absolutely within it.
  4. I added a little padding to the top of the container <div>, to give the head room to bob (no pun intended) up and down. In retrospect, I could have added some margin to the top instead, which would have slightly simplified the calculations of the image positioning. If you use the margin approach, make sure overflow is set to visible (which is default), else you’ll see some cropping.

We now have a static version of Bob to which we can add some CSS3 animation.

The Basics of CSS3 Animations

When it comes to creating CSS3 animations, we need to make use of the @keyframes rule. As the name suggests, @keyframes allow us to specify the key frames within the animation. The browser will then “tween” between the frames, i.e. it’ll automatically add the transition.

A simple example would be changing the background colour and font colour of a <div> when a user mouses over it.

Hover over me to see a CSS3 animation!

The above animation has 3 key frames:

  1. Initial frame – Dark blue background with white text.
  2. Intermediate frame – Light blue background with white text.
  3. Final frame – Light blue background with yellow text.

All we need to do is specify the above CSS styles within the @keyframes rule, and use percentages to define when those key frames should occur within the duration of the animation. For example 0% would be the start of the animation, and 100% would be the end.

Here’s the @keyframes rule for the animation above:

[css]
@keyframes example-animation{
0%{
backgound: #323a42; /* dark blue */
color: #fff; /* white */
}
50%{
background: #327bc4; /* light blue */
color: #fff; /* white */
}
100%{
background: #327bc4; /* light blue */
color: #ffe400; /* yellow */
}
}
[/css]

You’ll notice that I’ve put example-animation after @keyframes; this is the identifier for the animation and must be specified (obviously, you can name it what you want). It’s also worth noting that you must specify 0% (or the keyword from) and 100% (or to) as a bare minimum,  else the keyframes declaration is invalid.

You can find out more about @keyframes over at MDN.

I’m sure some of you may have already noticed, but there’s actually nothing in the code above to bind the animation to a specific element; all we’ve done is created a set of key frames. To attach it to an element we’ll need to use the animation property, which has the following syntax:

animation: name duration timing-function delay iteration-count direction fill-mode play-state;

So to attach it to our <div id="example-1"> upon hover over, we just add the following CSS:

[css]
#example-1:hover{
animation: example-1 2s; /* animate over 2 seconds */
}
[/css]

And we’re done!

Animating Bob’s Head

Now that we know how to go about creating CSS3 animations, let’s go ahead and animate Bob’s head. Here’s a timeline of what we plan to do:

Key frames - Bob's head

So at 0%, 50% and 100%, the head is at the default state, and at 25% and 75% the head is translated and rotated (see CSS3 2D Transforms for more information).

Here’s the @keyframes rules that’ll do exactly what I mentioned above:

[css]
@keyframes headBob {
0%,
50%,
100% {
transform: translate(0, 0) rotate(0);
}
25% {
transform: translate(-5px, -5px) rotate(-10deg);
}
75% {
transform: translate(5px, -5px) rotate(10deg);
}
}
[/css]

I think the code here is pretty self-explanatory, but a few things to note:

  • Translate moves the element along the x-axis (first argument) and y-axis (second argument). A positive value will move the element right/down, whereas a negative value will move the element left/up.
  • Rotate accepts one argument and will rotate in a clockwise fashion, unless a negative value is specified.
  • When specifying multiple transform functions, they should be separated with a space as shown above.

We can then attach it to an element using animation as previously mentioned. In this case we’re animating Bob when someone hovers over the canvas, so the following CSS will suffice:

[css]
#animation:hover #head {
animation: headBob 0.3s infinite;
}
[/css]

You’ll notice that I set the iteration-count to infinite, as I want Bob’s head to be bobbing the whole time the user’s mousing over the canvas.

Animating Bob’s Arm & Pancake

This is a little more tricky as we have to animate 2 image elements separately, while keeping them in sync. The timelines below should help clarify what we’re looking for. Please note that I’ve had to change the axis somewhat, so that the images fit!

Key frames - Bob's arm

Key frames - Bob's pancake

Let’s run through that again step-by-step:

  1. 0% – Bob’s arm is in it’s default state, i.e. level. The pancake is hidden behind the pan.
  2. 10% – At this point, Bob’s arm has been rotated by 15° anti-clockwise. The pancake is still hidden behind the pan. We can achieve this by translating it along the y-axis.
  3. 20% – Bob’s arm is back to it’s starting position (and will remain there until the end of this iteration). The pancake on the other hand has been moved up further, as well as rotated 360° anti-clockwise.
  4. 50% – The pancake is moved back down behind the pancake, having undergone a 720° anti-clockwise rotation.
  5. 100% – No change, to mimic a delay between the flicks.

Now that we’ve outlined the exact steps in the animation, the CSS is relatively easy to code up:

[css]
/* Keyframes for the flick of the arm */
@keyframes flick {
0% {
transform: rotate(0);
}
10% {
transform: rotate(-15deg);
}
20%,
100% {
transform: rotate(0);
}
}

/* Keyframes for the pancake spin */
@keyframes spin {
0% {
transform: translate(0, 0) rotate(0);
}
10% {
transform: translate(0, -25px) rotate(0);
}
20% {
transform: translate(0, -65px) rotate(-360deg);
}
50%,
100% {
transform: translate(0, 0) rotate(-720deg);
}
}

/* Attaching the animation to the relevant elements */
#animation:hover #arm {
animation: flick 1s infinite;
}
#animation:hover #pancake {
animation: spin 1s infinite;
}
[/css]

So now we’ve got the head bobbing, the arm flicking and the pancake flying, surely we’re done?

Try hovering over Bob below to see what we’ve done so far:

Pancake
Bob's arm
Bob's cooker
Fire
Bob
Bob's head

Oh dear! Bob’s got himself an extendable arm!

The problem we’re seeing above is due to the transform-origin property, which as it’s name suggests, defines the origin of the transform. This property defaults to the centre of the element in question and therefore Bob’s arm is rotating around the centre of the image of the arm.

What we actually need is for the transform-origin to be his elbow, as that’s the pivot. Let’s go ahead and change that property:

[css]
#animation #arm {
top: 122px;
left: 63px;
transform-origin: 0 41px; /* The new transform origin, i.e. the location of his elbow */
}
[/css]

And there we have it! A fully-functional animation of Bob making pancakes!

Pancake
Bob's arm
Bob's cooker
Fire
Bob
Bob's head

Here’s a download link in case you’d like to download all the assets (HTML, CSS and images) used in the tutorial. I’ve also included the .less file with custom mixins, that I used to create the CSS. If you’d like to learn more about Less, my colleague Andy wrote an awesome Introduction to Less, which should help you get on your way!

Thanks for sticking around until the end of the tutorial. Hopefully you’ve learnt a thing or two about CSS3 animations. As always, if you have any questions or constructive criticisms, please don’t hesitate to leave a comment below!

Contact