Responsive Sprite Animations with ImageMagick and GreenSock
CSS Sprites are not new. Since being popularized on A List Apart in 2004, the humble sprite has become a staple technique in many a web developer’s toolkit. But while the speed benefits afforded by sprites are well-understood, their uses in modern web animation are rarely discussed. The principle remains the same: combine multiple images into a single ‘master’ graphic, of which only selected portions are displayed at a time.
Building A Sprite
We need to combine each frame of our animation into a single image. There are dozens of tools out there to aid with the creation of sprites, many of which will even generate an accompanying stylesheet for you. Compass’s built-in spriting features are immensely powerful, and SpritePad is a good example of a web-based generator. For our purposes, however, a simple command-line approach works fine.
ImageMagick, the ‘swiss army knife’ of image processing, is a free and open-source image manipulation tool that’s perfect for automating tasks that could become laborious, such as combining images. ImageMagick is also available for just about every operating system. Mac users can install it via Homebrew, Windows adherents can download an executable installer from the official website, and Linux devotees probably don’t need me to explain anything.
Save the identically-sized frames of your animation in a folder as a sequence of PNGs. Break out a command-line terminal, navigate (
cd) to the directory where your images are saved, and execute the following command:
convert *.png -append result-sprite.png
This command instructs ImageMagick to vertically concatenate all the .PNG files in our directory (since ‘*’ is essentially a wildcard) into one complete sprite called “result-sprite.png”. This is the graphic that we will apply as a
background-image in CSS to the element we want to animate, altering its position to cycle through each frame in sequence.
Pure CSS Animation
We’ll start simply, and animate our sprite with CSS3 keyframe animation. If you’re unfamiliar with the basic syntax, Louis Lazaris’s article on Smashing Magazine is a very good introduction. We’re looking to animate the vertical
background-position of our element from 0% to 100% (top to bottom), exposing each frame in turn.
Allowing the animation to run in one continuous sequence, as per default behaviour, would expose our sprite’s in-between frames and ruin the illusion. By using the
steps() function, however, we can control the number of rendered keyframes. Because of the way
background-position works when defined as a percentage, we’ll need to set the number of steps to be one fewer than the total number of frames in our animation.
Experiment with the following CodePen to get the idea:
Note that we’ve defined the
height of our element to exactly match that of a single frame, to avoid any bleeding of prior or subsequent frames. We’ve used the shorthand notation to set the
animation-iteration-count to “infinite” and the
animation-duration to 3.5 seconds, with the result that Ryu will carry out his punch-kick-hadoken combo until the end of time.
This is far from perfect, however. Try changing the
height of our Ryu element, or applying a
background-size to our sprite, and the effect will break. Our animated element is not yet responsive, and is dependent on rigid, pixel-based dimensions.
Making it Responsive
If we wish to freely resize our animated sprite, we have two options. A key to both options is our sprite’s dependence on a consistent aspect ratio, rather than a particular size. We must retain its proportions for it to scale correctly.
The first option is to set the
background-size of our sprite to 100% of the width of our element, convert the
height of our element from pixels to ems, and then alter the base
font-size as required. This would achieve the desired effect, and may be suitable for most purposes, but would not result in true fluidity.
Our second option is to take advantage of Marc Hinse’s pure-CSS fixed aspect ratio technique, which uses percentage-based padding on a pseudo-element to maintain an element’s proportions at any size. This trick is used in the demo below to give our sprite a fluid width of 70%. Responsive Ryu.
This is a lightweight and mobile-friendly method of achieving a responsive frame-by-frame animation effect. Browser support for CSS animations is excellent, with the CSS3 keyframe syntax being the only limiting factor. Include the appropriate
-webkit- vendor prefix, and the effect works in all modern browsers including IE10 and above.
What if we want more precise control over our animation than is generally possible with the CSS3 keyframe syntax? Let’s say that instead of a single, looping animation, we wish to incorporate multiple sprites into a complex scene and bind triggers and timing functions to the position of the scrollbar?
These are powerful tools on which entire series of tutorials have been written. As such, rather than diving into the details of how to work with ScrollMagic, we will instead demonstrate some of the powerful timing functions now available to us. The basic sprite principles remain identical to our earlier pure-CSS animation.
First, let’s trigger a 2-second-long animation at a particular scroll position. It should finish on the final frame, and play in reverse when the user scrolls back up (even if this occurs midway through playback). We’ll stick with the video game theme and use a sprite from Westwood Studios’ strategy classic Red Alert, now released as freeware.
Note that we’re using the aforementioned em-based sizing method; try altering the
font-size to scale the sprite up and down. We’ve defined a
TweenMax.to tween, setting the destination value of our element’s vertical
background-position to 100%, and used the
SteppedEase method to achieve the required frame-by-frame effect.
Let’s take this one step further. We’ll synchronise our animation with the scroll position, using the scrollbar like a playback scrub control.
The sprite remains in a fixed position for the duration of the animation, which is now controlled by the user’s scroll behaviour. To achieve this effect, we’ve given our
duration of 1500px and used the
setPin method to fix the parent element for the entirety of the scene. For a more detailed breakdown of these techniques, be sure to peruse the excellent documentation on the ScrollMagic website.
We’ve barely scratched the surface of what’s made possible by combining responsive CSS sprites with advanced scrolling animation, but it’s my hope to inspire others to start experimenting. I’d love to see any sites that use variations of the techniques described above. You can take a look at the personal project that first prompted me to explore sprite animation — videogame aficionados may notice a pattern.
Finally, in the words of Rachel Nabors, “please animate responsibly.” Just because something can be animated it doesn’t necessarily mean it should be. And if you do choose to animate, do so deliberately, beautifully, and with purpose.
Thanks for reading!