Sprites aren't an outdated trick from the attic. They're often the more performant solution — and most developers don't even consider them.
That's a mistake.
#What Twitter understood in 2015
When Twitter introduced the heart button, the team faced a concrete problem. The new like animation consisted of 16 simultaneously animating elements: 14 particles, a popping circle, the heart itself. On low-end devices, that simply wasn't feasible — too many DOM nodes, too much compute load.
The solution didn't come from a new library. It came from the 90s.
A sprite sheet: all frames of the animation next to each other in a single image. CSS scrolls through the frames. The browser only ever renders a static image — no layout recalculation, no JavaScript, no canvas. The device only has to display one image and shift the position.
That's no magic. That's physics.
#Why this is still relevant today
I often hear: "But we have CSS animations, Lottie, GSAP." True. And for many use cases those are the right tools. But they all share one disadvantage: they work with the DOM or with JavaScript.
Sprites don't.
A sprite sheet is cached after first load. The animation runs via animation and steps() in CSS — done. No script has to load, no framework has to initialise. That's especially relevant for micro-animations that should respond to interaction. Like buttons, favourite icons, small feedback animations.
Exactly where you need speed and reliability, sprites deliver.
#How it works technically
The basic principle is simple. You take an image with all frames next to each other — the sprite sheet. Then you only show one section of it and move the image frame by frame.
Previously this was done with background-position and JavaScript timing. Today it goes cleaner: CSS animation with the steps() function jumps discretely between frames instead of interpolating fluidly. No JavaScript fiddling, no timing management.
.sprite {
animation: play 0.6s steps(10) infinite;
}
@keyframes play {
to { background-position: -1000px 0; }
}
That's it at the core. One image, one CSS property, one animation.
#The counter-argument — and why it doesn't hold
"Sprites are time-consuming to create. I need a finished asset." True. You need a sprite sheet, and someone has to build or export it. Tools like Adobe Animate, Aseprite or even After Effects with the right export can handle that.
But the effort pays off in certain scenarios. When an animation has to run on many devices simultaneously — for example in a list with hundreds of entries — a sprite is significantly cheaper than 16 animated DOM elements per entry.
Another counter-argument: "Lottie does that performantly too." Lottie is good. But Lottie needs a JavaScript library, parses a JSON file and then renders with canvas or SVG. That's more overhead than a cached PNG with two CSS lines.
For complex character animations or large illustrations, Lottie is the better choice. For small, frequently used micro-animations, sprites are often more efficient.
#When you should use sprites
Not always. But more often than you think.
Sprites fit well when you have an animation that has to run on low-end devices. Or when many instances of the same animation are on screen simultaneously. Or when you don't want to load JavaScript — for example in critical rendering paths.
They fit less well for large, detailed animations. There the sprite sheets quickly get big and eat bandwidth. Animations that have to respond to user input and vary dynamically also hit the limits of sprites.
#What you can concretely take away
First: know your toolset. Sprites exist. They work. They are the best option in certain contexts. Whoever doesn't know this automatically reaches for the heavier solution.
Second: ask yourself with every micro-animation whether you really need JavaScript. Often not.
Third: look at what browsers have been able to do for a long time, before you include a new library. steps() in CSS is no secret tip — it's just too little known.
Twitter didn't optimise an algorithm in 2015. They pulled an old trick off the shelf and applied it to a modern problem. That's good engineering. Not taking the newest, but the right thing.