CSS3 Sprite Animations With Steps()... Almost

I’ve recently been poking around with sprite animation for a new version of this site (more on that later), and since I’m trying to show off my cutting-edge front-end chops I wondered if there was a way to accomplish this animation without using JavaScript. And there is! Sort of.

Obviously CSS3 Animations and Transitions have been around for a while, but sprite animation relies on moving an element’s background-image in a series of steps, with each step corresponding to the frame width. A typical animation/transition setup in CSS results in a smooth change of a given property, which won’t work for our purposes. A quick search showed that someone wrote about their attempt at this a while back, but the solution struck me as a bit hacky and incomplete.

I then came across this jsFiddle, where someone has had a go at implementing this idea using the recently-specified steps() timing function. According to the Animation and Transition specs, this function takes two parameters, and:

The first parameter specifies the number of intervals in the function. […] The second parameter, which is optional, is either the value ‘start’ or ‘end’, and specifies the point at which the change of values occur within the interval.

Combining this with the size of and number of frames in a sprite, it’s possible to have CSS perform the animation for us. With a 1000px-wide sprite, a timing function of steps(9, start) applied to a transition to background-position: -900px (one frame less than the total width so as to leave the final frame visible) is enough to get it working.

So that’s great, right? Well, sort of. It turns out that this works fine in situations where the transition has enough time to complete before being reversed again. However, I was triggering a transition on hover, and if my pointer left the element before the transition was complete it would immediately reverse without “snapping” to the nearest step in the transition, showing partial frames in the background and breaking the animated effect.

The spec acknowledges the problem of reversing timing functions but does not yet supply a recommended solution. I tested briefly in Chrome, Safari and Firefox and none seemed to correctly reverse the steps() function. The most visually pleasing solution, I would have thought, would be to jump to the nearest transition/animation step and reverse from there, but perhaps it’s not that simple. Either way, it doesn’t currently work properly in the browsers I tested.

If, however, your situation allowed a transition more time to complete – for example, a non-hover situation, like adding a class on click or within a media query, this should work fine for you. The problem only arises when the transition or animation is interrupted part-way through.

For the time being, then, I’m using a quick bit of JS to accomplish this effect, but I’m keeping an eye on developments in the Animations and Transitions modules hoping this might get a fix sometime.