Staggering Animations

Avatar of David DeSandro
David DeSandro on (Updated on )

The following is a guest post by David DeSandro. David wanted to offer a new feature in Isotope: staggered animations. Like so many things web, there are lots of ways he could have approached it. Here he looks at some of the possibilities, the advantages and disadvantages of each, and what he ultimately went with for Isotope.

Consider this cinematic Seinfeld moment:

The image of George running through a group of gulls stirs the emotions. The energy in his conviction is matched by the bursting energy of the birds. So how can we animate with this kind of energy?

George Costanza running through birds

Take another look at those gulls. It’s not that there’s a lot of them. The birds take flight individually. As each one flies, their numbers in grow, and the emotion lifts off with them. Go get ’em George!

Instead of animating a group of items all at once, we can recreate this same effect by staggering the animations. When each item’s animation is incrementally delayed, they appear as individuals, but still move collectively as a whole. The result is captivating and feels more true to life.

I recently released Isotope v3 with new staggered item transitions.

See the Pen Isotope – stagger by David DeSandro (@desandro) on CodePen.

While item transitions are easy to set up, they can be difficult to manage. Running multitudes of animations at different intervals gets complex. So let’s explore how to stagger item transitions.

We’ll used a simple animation for our example: moving a group of items horizontally. Items have CSS transition: transform 0.4s;. They move by toggling .is-moved class. The first demo moves all the items at once.

See the Pen single transition by David DeSandro (@desandro) on CodePen.

setTimeout

We can use setTimeout to stagger triggering the transitions. setTimeout will start the transition later with a delay in JavaScript.

See the Pen setTimeout by David DeSandro (@desandro) on CodePen.

This actually looks pretty good. To fine tune the animation, I want the items to move without overlapping. So items on the right start moving first when moving to the right. Items on the left start moving first when moving to the left. We need to reverse the setTimeout delay if moving to the right.

See the Pen setTimeout, forward & reversed by David DeSandro (@desandro) on CodePen.

Not bad! But now comes the premier test of any animation system: What happens when a change is triggered while animating? This edge case is too often overlooked. Any novice developer can add an animation. But if you care about your users, your animations should react instantly when acted upon. Animations should not impede on your users actions.

Try clicking the button while transitioning to see what happens.

It works. All the items end up where they are supposed to. But I don’t like how it behaves. It looks like the items get confused. Also try the non-reversed demo.

The forward/reversed transition continues through all the items. This isn’t good. The animation is still happening after the user has already reversed their action.

transition-delay

Let’s try something else. We’re already using CSS transitions, so it makes sense to use transition-delay. This demo uses JavaScript to set the incremental transition-delay in JS (but you could also use CSS preprocessor logic if that’s your thing). The transition is triggered at the same time for all items, but their delay differs by their transition-delay value.

See the Pen transitionDelay by David DeSandro (@desandro) on CodePen.

We can reverse the delay, to have similar behavior moving left and right, just like the setTimeout demo.

See the Pen transitionDelay, forward & reversed by David DeSandro (@desandro) on CodePen.

As for start-stopping, this transition-delay demo behaves differently. The forward/reversed demo stops in place for moment.

This could work, but its behavior still isn’t ideal.

Frame-based animation

There’s one more method to try out: frame-based animation. Using requestAnimationFrame allows us to have control of how each transition is triggered, when it is triggered.

See the Pen frame animation by David DeSandro (@desandro) on CodePen.

It’s got perfect behavior. Start-stopping reverses the animation right where it is, so there is no delay and no excess transitions. But this nice result comes at the cost of complexity. This demo requires double the amount of JavaScript, with an animation loop that has to run every frame.


So if you want to stagger animation, you’ve got options.

  • setTimeout will work, but is hard to cancel.
  • transition-delay will work, but might have delays.
  • requestAnimationFrame will work, but requires more JavaScript.

And there are lots more solutions out there: CSS animations, jQuery .animate(), GreenSock, D3, yada, yada, yada. All these solutions can be used for staggering animations. But I encourage you to investigate how well they hold up to edge cases when user actions occur during the animation.

Working on Isotope, I chose to use the transition-delay technique. It provided the best level of control, without too much complexity. Now Isotope users can add the final level of polish to their UI and take their experiences to new levels. Like a Costanza chasing his dreams.