JavaScript Animation That Works (Part 1 of 4)

HTML is the language that the web is built in and it's kind of a strange beast. Although it was originally intended as a way to easily share academic information across the Internet, it has been slowly transformed to accommodate the media-rich environment we know and love. Because of the haphazard nature of HTML (and JavaScript, the programming language that manipulates elements in HTML and makes them interactive), sometimes we have to think outside the box a bit. In this tutorial series, I will show you how to do cross-browser animation using a method called spriting. And, because this is a learning opportunity, we will be doing it all without any external libraries (like jQuery).

This will be a four-part series. I'll explain the spriting itself in part one (this article) with some basic JavaScript, but then in later installments we will move into some intermediate techniques like encapsulation, event handling, and touch screen support.

So let's get started!


What Is Animation?

Animation is based on a phenomenon called persistence of vision, which basically says that if your brain sees lots of similar still images fast enough, then it will appear as though it is one moving image. Every kind of film or video uses this basic technique—many slightly different frames are shown in quick succession to make something appear to be moving. Film typically runs at 24 frames per second (₁), while broadcast television in North America is shown at 29.97 frames per second (₂). So, in other words, what we want to do is create something that shows similar frames really quickly (several times a second).


The Difficulties on the Web

There are two main reasons animation is difficult to use on the web:

  1. The first is that different web browsers have different ways of interpreting HTML and JavaScript, so what works on one device often doesn't work on another. Flash works great on most browsers, but support is starting to drop for it and iOS devices won't allow it at all. Canvas has a lot of potential, but Internet Explorer 8 doesn't support it. Same goes with Adobe Edge Animate. GIFs work on everything, but you can't control the animation or make it interactive.
  2. And for the second, every time an image is served on a web page, a separate request is made between the browser and server. These requests can add up, even over a lightning fast Internet connection, making having several frames each second unmanageable.

The Solution: Spriting

One way around these problems is to make a sprite sheet. In elements like divs, we can set a background image for the div that may be larger than the element itself. We can also set the background position so that we determine exactly which part of the larger image will show. A sprite sheet is a larger image made of several smaller images that we can move around so that it could take the place of many small images. Take a look at the example below, using J, the mascot of my company Joust Multimedia:

javascript-spriting-j

Although there are ten different images of J, they are placed together on one larger PNG file (we are using PNGs because they can show transparency). If we have a div that is only the size of one of the images, and we set this PNG as the background, it will look like a single image.

See the hazdm on CodePen.

Although this seems like a lot of trouble to go through to show an image, this method nicely fixes the two issues we had before. With very little JavaScript (one line!) you can change the background position of a div, and it works on everything. Also, since all of these frames are on the same image, it will only take one request to load that image in the page. So, once the page loads, it can switch between sprites with no problem at all.

So how do we set this up to animate easily then? The first step is to create the sprite sheet. You will want to know what the final dimensions of your image should be, and space the sprites accordingly in a grid. For instance, my J image is going to be 40px wide by 50px tall, so I lined up my sprites exactly 40px apart horizontally and exactly 50px apart vertically. It will probably be easiest if you set your starting sprite in the upper left corner.

Then we will set up a div with a bit of CSS to make sure that everything appears properly:

And here is our CSS to make sure the sprite is showing correctly:

Notice the following things:

  • We specify the width and height of the div to the size of our sprite
  • We specify the background-repeat to 'no-repeat'
  • We specify the background-position to '0 0'—this will show the sprite in the top left corner

Now, it will just take a single line of JavaScript to change the background position to show the next sprite.

Here, we are selecting the element (with id='j'), and setting the style attribute 'backgroundPosition'. Notice that it is spelled 'backgroundPosition' in JavaScript, and not like 'background-position' in CSS. Also notice that in JavaScript, the 'px' is required for both the x and y amount—we cannot just pass it numbers. And because we are moving the background image, we have to move it in the opposite direction from what you might expect. To move to the sprite on the right, we have to have the image move 40px to the left.

Now, if we just have something simple to execute this code (like a button), we can see the frames changing in action: checkout the DIsgk on Codepen.

Additionally, you might be interested in taking a look at the source code for this page as well. It has all of the examples here with thorough comments. And here's the sprite sheet I am using.

Next Up

What we've covered in this tutorial is a good start, but it isn't really a proper animation. In part two of this series we will actually animate some running and jumping, by creating loops with the different sprites.

By part four, we will be creating mouseovers for a bit of robot action. See the ByGtv Codepen for a preview.


Conclusions & Drawbacks

Although this can be a great method for animating on the web, there are a few drawbacks. First, it can require you to create each individual frame of animation, which can be time-consuming. Second, browsers don't have the most accurate of timers for animation, so if it is critical for your animation to be timed perfectly, then this may not work. Finally, mobile Safari (used on iPhones and iPads) has a “feature” where if you have a background image that is either larger than 2MB or larger than 1024 x 1024 x 3 pixels (or 3,145,728 total pixels), it will automatically rescale the image, ruining the spriting effect. This means that really large sprites, or animations with a very large number of sprites, are out of the question. But, for simple, small animations that you want to be very interactive, this is an easy and great way to get something that works everywhere.

Interesting Side Notes

1. Before sound was introduced with film, there wasn't really a standard frame rate. The cameras were operated by a hand crank, so if you had a rookie cameraman the frame rate might slow down and speed up unintentionally. Similarly, less reputable theaters were notorious for telling their projectionists to crank the projector quicker to speed up the show so they could fit in more screenings. This is also why we stereotypically think of pre-sound movies as moving around comically fast—most were filmed around 16 to 18 fps, so when we play them today at 24 frames per second, they are moving faster than they were originally intended.

2. Television was originally broadcast at 30 fps in North America, but color television caused a glitch when shown at that speed. Engineers figured out that they could fix it by slowing down the frame rate by 0.1%, which is why it is now set at 29.97 fps. Also, besides all of the wacky technical issues involved with converting a film in 24 fps to display on television at 29.97 fps, showing television at a faster fps has had an interesting effect on the public. Many people watching the test screenings of “The Hobbit” at 48 fps reported that the increased frame rate made the film look “cheaper”, even though it was much higher quality than a typical film, just because they had grown to associate faster frame rates with watching something on television.

Tags:

Comments

Related Articles