Sunday 19 August 2012

The Pie Guy (CSS Keyframe animations)

I've had a few quiet days at work and have taken the opportunity to play around with some new toys that no one has wanted me to use professionally yet. I've seen a few examples of keyframe animations recently, but the most I've ever done is move a div around the screen, changing it's colour, and resizing it. I was showing this off to a colleague who then (jokingly) said that I should create a man who eats pie and then gets fat. So that's just what I did...

The HTML is extreme divitis. No content at all, so I'm going to ignore it exists. The CSS is quite complex as everything happens there. Mainly the code is colouring, sizing, and positioning. Pretty simple and standard stuff.

The fun begins when declaring the keyframes. No browser currently supports this without a vendor prefix, but they all work in the same way. I'm a firm believer in vendor prefixes as it means us web devs don't have to employ weird hacks to get our code working cross browser. It does become frustrating though when the code is exact duplication. Our friend IE doesn't support this until 10, so it's worth putting in the -ms- prefixes for when the time comes.

My page has three animations. The pie moving into the mouth, the mouth opening and closing, and the belly expanding. Let's start with the pie.

@-webkit-keyframes pie
{
0%
{
left: 250px;
opacity: 1;
}
50%
{
left: 140px;
opacity: 1;
}
60%
{
left: 140px;
opacity: 0;
}
100%
{
left: 140px;
opacity: 0;
}
}


What you see here is only the -webkit- prefixed version, you will also need to include -ms-, -moz-, and -o-.

You only need to define two steps in a keyframe, 0% and 100%. The browser then works how to transition between the two, and does so. If you want stops then you need to define them. Later on we look at the timing, which will be when you refine the position of the stop.

Any properties that have no transitional states are ignored. The pie disappears as the Pie Guy eats it. My first thoughts were to use display:none/block, but nothing happened as the browser doesn't know how to transition between the two. I instead had to use opacity, which gives a nice fading effect that I now think is better.

Code for the mouth:

@-webkit-keyframes mouth
{
0%
{
}
20%
{
height: 7px;
}
35%
{
height: 25px;
}
55%
{
height: 25px;
}
63%
{
height: 7px;
}
100%
{
}
}


Code for the belly:

@-webkit-keyframes belly
{
0%
{
width: 130px;
left: 93px;
}
60%
{
width: 130px;
left: 93px;
}
65%
{
width: 145px;
left: 85px;
}
100%
{
width: 145px;
left: 85px;
}
}


I want the mouth and belly to be coordinated with the pie. If I give them the same length of animation time then I can use the stops to easily coordinate the animations. For the mouth I'm happy for the default styling to be in place until it opens for the pie. The belly section is hidden by the torso section until it expands from the amount of food that has been eaten.

This is all well and good, but I can't tell where these stops really need to be without watching the animation happening in the browser. In order for that to happen the keyframe needs to be called by an associated selector. Again, this is all browser prefixed in the same way as keyframes. This is the declaration for the mouth; the pie and belly are similar.

#mouth {
    -webkit-animation: mouth 10s;
}


The declaration first references the keyframe to be used, then the duration it runs. There are other options that I've not used here as I'm happy with the defaults. These are:

  • Timing function; specifies the speed curve of the animation
  • Delay; specifies a delay before the animation starts
  • Iteration count; specifies how many times the animation runs (default is once)
  • Directioin; specifies if the animation should run in reverse

Back to the pie guy specifically. I want the mouth opening/closing and the belly growing to happen sequentially (rather than the guy getting fatter as he's eating the pie) so I've offset the stops slightly in the keyframe. I started this with quite broad stops, having one at every quarter. To get the timing right took some playing around. I would make an adjustment, watch it run, and then adjust again until I was happy with the timing that you see today.

Further thoughts

Although this is pretty cool, it's rather frivolous. Let's face it, no brand is going to want the pie guy as their mascot. Just look at his hair! However, animations can be used really subtly to replace minor usability that we used to ask of flash, and in a much lighter way that even smart phones can run. I look forward to seeing marketers using animations for pulsating buttons, attracting the user's attention to the desired next action.

As interface developers we should be thinking about how we can tell the user through visual effects that we've registered their interaction with the page. If there is a delay between the user's action and the reaction from the page, we could reduce the feedback gap through animations. The animation declaration could be attached to a selector that doesn't reference anything in the DOM on page load. Once the user has interacted with the page, we can add the class to an element to trigger the animation to start. To do this we would need to employ a small amount of JavaScript, but that's not a big deal for the modern devices that can run keyframes. Older browsers where users are likely to have JavaScript turned off are unlikely to be able to run keyframes, so the effect would be lost on them anyway.

Let me know if you can think of any other real world applications of keyfrmaes that we can use today.












No comments:

Post a Comment