Animating a CSS Sprite With JavaScript

Take a look at this demo, and guess how the animation is achieved. It’s not an animated GIF. It’s a PNG sprite that is brought to life with a little bit of JavaScript.

The sprite image is a long strip containing each frame of the animation. The stylesheet sets it as the background of a DIV, and the dimensions are set so you can only see one frame at a time. Then a script uses a timer loop to continuously shift down the line, resetting once it reaches the end. (A more complex version of this effect can be seen in this Google Doodle.)

It works just like the sprites traditionally used in video games. It’s more efficient to load one image from a slow data source, whether it’s a hard disk or an internet connection, and only show a piece of it at a time, than to load dozens of images and alternate between them. (It saves some overhead in other ways in a performance-minded environment like a game, as well.)

Why not just use an animated GIF?

Aside from the simple fact that it’s more fun, the Graphics Interchange Format has some limitations that make it unsuitable for certain applications. It doesn’t work very well at all for photographic images, and it only has very basic transparency support. JPEG is far better for photographs, and PNG for images with flatter colors.

There is another image format that supports animation, the animated PNG format (APNG), but support for it is sorely lacking. Most popular image editors don’t support it natively, and only a couple of browsers can display them without third-party extensions. Firefox/Gecko and Opera are about the extent of browser support for APNG. Internet Explorer can’t display them at all, and Chrome requires a third-party extension.

By using a sprite, you have an image format that fits your needs, and still have animation. Oh, and you can start and stop the animation at will, through JavaScript.

Implementation

For starters, you need an element to hold the sprite. I ended up using a DIV with an ID of “sprite.”

<div id="sprite"></div>

Then you need to style the element. (If it’s not already a block-level element like a DIV, you may need to add display:block.) It’s height should be the height of your sprite image, and the width should be the width of a single frame. My image is 200 pixels high, and a frame is 300 pixels wide.

#sprite {
width: 300px;
height: 200px;
margin: 30px auto;
background-image: url(sprite.png);
}

The most important part, of course, is the script. I’m using some jQuery, simply because it’s a convenient way to handle my button events. You could easily adapt it to work without, though.

$(document).ready(function(){

var frameWidth = 300;
var frameHeight = 200;
var spriteWidth = 5400;
var spriteHeight = 200;
var spriteElement = document.getElementById("sprite");

var curPx = 0;
var ti;

function animateSprite() {

spriteElement.style.backgroundPosition = curPx + 'px 0px';
curPx = curPx + frameWidth;

if (curPx >= spriteWidth) {
curPx = 0;
}

ti = setTimeout(animateSprite, 80);

}

animateSprite();

});

The block of variables at the top set the frame dimensions, the dimensions of the sprite image, and the element containing the sprite. Then a timer is set, firing once per 80 milliseconds, which runs the animateSprite() function. Every time the function runs, it sets the background offset to curPx, and adds the frame width to curPx, so the next frame will be displayed in the following iteration. If curPx reaches the last frame, it’s reset to zero, so the animation will wrap around.

As an added bonus, you can start and stop the animation at will through the script. I just added some click events to a couple of links for illustrative purposes.

$("#stop").click(function() {
clearTimeout(ti);
});

$("#start").click(function() {
ti = setTimeout(animateSprite, 80);
});

You can see the finished example in action here.

  • http://www.lookpak.com Salman

    thanks… very helpful for me…

  • Angeline

    Hmm… Didn’t work for me, did I miss something?

    , yes?

  • juju

    good tutorial

  • Robert

    Thanks for the tip; one note: the animation is actually playing backwards. To play forwards you need a negative x coordinate, like so:

    spriteElement.style.backgroundPosition = ‘-‘+ curPx + ‘px 0px';

    • http://derangedscratchings.blogspot.co.uk DigitalDesperado

      Thanks for that. Also it is not playing backwards as Robert suggests, I’m an animator and I’m using it to run an animated sequence and it plays forwards. You do not need to alter the code.

  • http://derangedscratchings.blogspot.co.uk DigitalDesperado

    ….ok it is playing backwards. I eat my words sorry Robert. However I couldn’t get your fix to make it play forwards it just stopped working for me. I used this instead
    curPx = curPx – frameWidth;

    If nothing else it’s good to know how to make it play either backwards or forwards.

  • Tim Sweet

    I made a little animation plugin animatinator

    http://timothyswt.github.io/animatinator/#/home

  • Moises Lagos

    if the image is vertical as I do?

  • http://slicker.me/ SoftwareForChildren

    Thanks for the good information!

    Here’s a similar tutorial (only about 15 lines of code), without jQuery:

    http://sprite.slicker.me/tutorial/tutorial.htm