Tuesday, April 10, 2012

CSS3 Animation and Transitions Tutorial: Soccer Ball Animation

In this post we’ll show you how we created a soccer ball animation using CSS3 animation and transitions. We’ll do this in 6 steps. You can see each step as well as the final result here (you’ll need a screen width of 1650 pixels or more).

The soccer ball shoots up into the air from the left side of the field and goes back down to the right side of the field. This goes back and forth for a total of 3 animations. There is also a transition you can trigger once the animation completes: hovering over the ball hurls it up into the face of a spectator in the foreground at bottom right.


Here are the steps:

1. Setting up a Foundation with Modernizr
2. Animating Size
3. Animating Position
4. Animation Rotation
5. Supporting Multiple Browsers
6. Adding a Transition


Step 1: Setting up a Foundation with Modernizr

In Step 1 we start with a basic page that has a div with an image for the soccer field (‘field’) and another with an image for the ball (‘ball’).

DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"  class="no-js">
<head>
...
<head>
<body>

<div id="notsupported">Sorry, Your Browser DOES NOT Support CSS Animations and Transitionsdiv>
<div id="supported">Yay, Your Browser DOES Support CSS Animations and Transitionsdiv>

<div class="field">
    <img src="background.jpg" alt="field" />
div>

<div class="ball">
    <img src="ball.png" alt="ball" />
div>

<body>
<html>

We want to use the Modernizr library to test for the availability of the features we need, which in this case is css animations and transitions.  We include it in the area of our page.

<script src="http://ajax.aspnetcdn.com/ajax/modernizr/modernizr-2.0.6-development-only.js" type="text/javascript"<script>

If css animations and transitions are not present, we want to display the following red sorry message and hide the field and ball.


If we do have animations and transitions available, we display a green confirming message, show the field and ball:


We accomplish this with the following CSS styles. This works because Modernizr will set classes on the element with names like cssanimations, no-cssanimations, etc. based on the features it detects.

  <style type="text/css">

    /* Display whether or not CSS Animations and Transitions are supported */
     
    .cssanimations #notsupported {
        display: none;
    }

    .cssanimations #supported {
        display: inline;
        padding: 8px;
        background-color: green;
        color: white;
        font-family: Sans-Serif;
    }
       
    .no-cssanimations #notsupported {
        display: inline;
        padding: 8px;
        background-color: red;
        color: white;
        font-family: Sans-Serif;
    }

    .no-cssanimations #supported {
        display: none;
    }

    .no-cssanimations .field {
        display: none;
    }

    .no-cssanimations .ball {
        display: none;
    }


    .csstransitions #notsupported {
        display: none;
    }

    .csstransitions #supported {
        display: inline;
        padding: 8px;
        background-color: Green;
        color: White;
    }
       
    .no-csstransitions #notsupported {
        display: inline;
        padding: 8px;
        background-color: Red;
        color: White;
    }

    .no-csstransitions #supported {
        display: none;
    }

    .no-csstransitions .field {
        display: none;
    }

    .no-csstransitions .ball {
        display: none;
    }


    /* Image of soccer stadium, field, and crowd */

    .field {
        position: absolute;
        top: 150px;
        left: 0px;
        height: 300px;
        width: 1500px;
        text-align: left;
    }


    /* Ball container */

    .ball
    {
        position: absolute;
        top: 300px;
        left: 700px;
        height: 200px;
        width: 200px;
    }


    /* Ball image */

    .ball img
    {
        max-height: 100%;
        max-width: 100%;
    }

  <style>

When we run this in common browsers, we get the red not supported message in IE9 and the green confirming message in IE10, Chrome, Firefox, and Safari.


Step 2: Animating Size

Now we want to put some animation in place, starting with the size of the ball. To do CSS animation today, you need to use vendor prefixes since theimplementations are pre-ratification of the standards. That means instead of using style properties like animate: we’ll be using –webkit-animate for web kit (Chrome, Safari), -moz-animate for Firefox, and –ms-animate for IE. For now, we’ll just put in the –webkit prefix and add the others in a later step.

In the CSS, we achieve the animation by defining a keyframes animation (‘throwing’) and then referring the animation in the style rule for ball. Let’s parse the animation reference in the .ball rule first. The line below means, for webkit browsers, apply the animation ‘throwing’ over a duration of 10 seconds, do it three times, and alternate direction every other time.

-webkit-animation: throwing 10s 3 alternate;

The keyframes animation indicates changes at 0%, 50%, and 100% of the animation. Size goes from 5px height and width to 200px at the midpoint and back down to 5px at end. This gives the effect of a ball getting closer and closer at it soars toward us, then falls back again down to the field.

    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; }
        50% { height: 200px; width: 200px; }
        100% { height: 5px; width: 5px; }
    }

Animating size is a good first step, but we’ll need to animate some other characteristics in order to make this effect more convincing.



Step 3: Animating Position

Now that we have the ball size animating, let’s control the start, middle, and end position of the ball to correspond with areas of the background soccer field image. To do this, we simply expand the keyframes animation to also modify the top and left positions.
    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { height: 200px; width: 200px; top: 50px; left: 800px }
        100% { height: 5px; width: 5pxtop: 400px; left: 875px }
    }

Now our ball grows in size and has a movement path that aligns with the background. It even pops out of its bounding frame, seemingly.


Step 4: Animating Rotation

A final touch on the animation is to have the ball rotate. We can achieve that by also adding a transform that rotates the ball. We’ll rotate to 180 degrees by midpoint and on to 360 by the end.

    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -webkit-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -webkit-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }



Step 5: Supporting Multiple Browsers

Up till now we’ve just been putting the –webkit-xxx animation keywords, which gets us working in Chrome and Safari. Now we want to support Firefox and IE as well. We’ll do that by adding –moz-xxx and –ms-xxx keywords. Here’s our updated style.

  <style type="text/css">

    ...

    /* Ball container */

    .ball
    {
        position: absolute;
        top: 400px;
        left: 875px;
        height: 5px;
        width: 5px;
   
        -webkit-animation: throwing 10s 3 alternate;
        -moz-animation: throwing 10s 3 alternate;
        -ms-animation: throwing 10s 3 alternate;
        animation: throwing 10s 3 alternate;
    }


    /* Ball image */

    .ball img
    {
        max-height: 100%;
        max-width: 100%;
    }


    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -webkit-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -webkit-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @-moz-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -moz-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -moz-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @-ms-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -ms-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -ms-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

  <style>

Now we can perform the animation with IE10 and the latest versions of Chrome, Firefox, and Safari. If we wanted to also support Opera or additional browsers that support animation, it’s just a matter of also including their prefixes as well.


Step 6: Adding a Transition

We’ve done animations up till now, which are applied immediately upon definition. Transitions, in contrast, are trigged by some action. We’ll add a transition that hurls the ball into a spectator, and we’ll trigger it when the ball is hovered over.


We define a hover style rule for ball that changes position, size, and rotation:

    /* Hover transition */
   
    .ball:hover
    {
        height: 200px;
        width: 200px
        top: 480px;
        left: 1100px;
   
        -webkit-transform: rotate(360deg);
        /* -moz-transform: rotate(360deg);  <= breaks hover transition in Firefox, presumably a bug */
        -ms-transform: rotate(360deg);
        transform: rotate(360deg);
    }

We then reference the transition in the rule for ball, specifying a 10 second duration.

    /* Ball container */

    .ball
    {
        position: absolute;
        top: 400px;
        left: 875px;
        height: 5px;
        width: 5px;
   
        -webkit-animation: throwing 10s 3 alternate;
        -moz-animation: throwing 10s 3 alternate;
        -ms-animation: throwing 10s 3 alternate;
        animation: throwing 10s 3 alternate;
   
        -webkit-transition: all 10s;
        -moz-transition: all 10s;
        -ms-transition: all 10s;
        transition: all 10s;
    }

Here’s the updated style:

  <style type="text/css">

    ...

    /* Image of soccer stadium, field, and crowd */

    .field {
        position: absolute;
        top: 150px;
        left: 0px;
        height: 300px;
        width: 1500px;
        text-align: left;
    }


    /* Ball container */

    .ball
    {
        position: absolute;
        top: 400px;
        left: 875px;
        height: 5px;
        width: 5px;
   
        -webkit-animation: throwing 10s 3 alternate;
        -moz-animation: throwing 10s 3 alternate;
        -ms-animation: throwing 10s 3 alternate;
        animation: throwing 10s 3 alternate;
   
        -webkit-transition: all 10s;
        -moz-transition: all 10s;
        -ms-transition: all 10s;
        transition: all 10s;
    }


    /* Ball image */

    .ball img
    {
        max-height: 100%;
        max-width: 100%;
    }


    /* Animation keyframes */

    @-webkit-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -webkit-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -webkit-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @-moz-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -moz-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -moz-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @-ms-keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { -ms-transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { -ms-transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }

    @keyframes throwing {
        0% { height: 5px; width: 5px; top: 580px; left: 660px }
        50% { transform: rotate(180deg); height: 200px; width: 200px; top: 50px; left: 800px }
        100% { transform: rotate(360deg); height: 5px; width: 5pxtop: 400px; left: 875px }
    }


    /* Hover transition */
   
    .ball:hover
    {
        height: 200px;
        width: 200px
        top: 480px;
        left: 1100px;
   
        -webkit-transform: rotate(360deg);
        /* -moz-transform: rotate(360deg);  <= breaks hover transition in Firefox, presumably a bug */
        -ms-transform: rotate(360deg);
        transform: rotate(360deg);
    }

  <style>


Summary

CSS animations and transitions are extremely powerful and fairly easy to learn, but their lack of ubiquity requires discipline in checking for feature availability for which Modernizr is invaluable. A good animation or transition needs to be planned out and storyboarded, much like a movie scene, before it is clear what needs to be done to cleanly implement it.

To see the source, visit the online demo, pull up any of the steps, and view source (each is a single page).

1 comment:

Anonymous said...

Demo is down. :(