Friday, March 23, 2012

Flash-like keyframe animation in CSS3 without tweening

Six years ago I created an animation of a 'dancing' monkey in Adobe Flash. The animation consisted of a sequence of images of a cartoon monkey in five different positions. By showing the images one after the other, with a short delay after each step, it looked like the monkey was, uh... dancing. In cartoon world everything is possible, right?

This week I have been busy writing a hangman type of game for my daughter in HTML5 and CSS3. I wanted to include the same dancing monkey animation that I created in Flash, to be shown when the game is won. It is said that HTML5 (and CSS3) are already able to do what Flash can do, so I have started to experiment with CSS3 keyframe animation.

During my exercise I stumbled upon something very basic that can easily be done in Flash: I did not want tweening (in motion or shape) between a keyframe and the next. In Flash, if I want tweening to occur, I have to define it explicitly between two keyframes. In CSS3 tweening occurs automatically and I have to take action to prevent it.

Take the following simple example that moves a green square from left to right (tested in Google Chrome, hence the '-webkit' prefix):
#square {
    width: 100px;
    height: 100px;
    background: #006600;   
}

#square.animated
{
    -webkit-animation-name: animation;
    -webkit-animation-duration: 2s;
    -webkit-animation-timing-function: linear;
    -webkit-animation-iteration-count: infinite;
}

@-webkit-keyframes animation
{
    0% {
        -webkit-transform: translateX(0px);
    }
    25% {
        -webkit-transform: translateX(50px);
    }
    50% {
        -webkit-transform: translateX(100px);
    }
    75% {
        -webkit-transform: translateX(150px);
    }
    100% {
        -webkit-transform: translateX(200px);
    }
}
I have created a jsFiddle that illustrates this example. Note that, though I did not define any tweening between the five keyframes, the green square moves fluently from left to right. Often this is just what you want, but sometimes... it is not!

To get rid of the tweening we take advantage of the fact that CSS3 keyframe percentages may contain decimal values. We change the keyframes section in our CSS as follows:
@-webkit-keyframes animation
{
    0%, 25% {
        -webkit-transform: translateX(0px);
    }
    25.1%, 50% {
        -webkit-transform: translateX(50px);
    }
    50.1%, 75% {
        -webkit-transform: translateX(100px);
    }
    75.1%, 100% {
        -webkit-transform: translateX(150px);
    }
}
The effect of the changes is demonstrated in another jsFiddle. As you can see, the square stays motionless from 0%-25%. Then suddenly at 25.1% along the timeline, we shift the shape 50 pixels to the right. We leave it there untill the 50% mark before shifting it to the right again at 51.1%. The 'magic' lies in snapping each new frame into place so quickly that you cannot see the in-​​between state.

No comments:

Post a Comment