The world seems obsessed with this idea that users don't want to see loading spinners if the loading process will only take a fraction of second. A few years ago, I demonstrated that this kind of delay can be accomplished with a simple CSS
animation-delay property; but, in that post, I assumed that the loading indicator itself had no animation. That said, even if the loading indicator does have an animation, we can still use the same technique by applying multiple animation
@keyframes to the same loading indicator using CSS.
In my previous post, I used the
animation-delay to keep the loading indicator at
opacity:0 for a few hundred milliseconds. And then, I faded the indicator into view using
opacity:1 and just left it there as a static element on the page.
In reality, my loading indicator, itself, has some sort of "pulsing" animation to it - an animation that has to repeat infinitely. As such, I can't include the
opacity in that pulse
@keyframes otherwise the indicator will fade in-and-out infinitely. Luckily, we can apply multiple
@keyframes to a single element. And then, we can use comma-delimited sets of properties to define the behavior of each individual animation.
This means that we can have one
@keyframes that defines the "fade in" animation which runs only once. And, we can use a separate
@keyframes to define the "pulse" animation which will run (iterate) infinitely. Then, we can use the
animation-delay on both animations to keep the loading indicator hidden briefly before it fades in and starts pulsing ad infinitum.
To see this in action, I've put together a simple jQuery demo in which I can add and remove a loading spinner to and from the DOM (Document Object Model), respectively. The spinner then uses two different animation
@keyframes, one that faces the indicator in once, and one that translates it horizontally back-and-forth forever:
As you can see, our first
opacity to manage the visibility of the loading indicator. And, our second
transform to give the loading indicator a little razzle-dazzle once it's rendered to the user. Inside of our
.spinner style block, we then use a comma-delimited value for our
animation-iteration property in order to make sure that the fade-in animation only runs once while the razzle-dazzle animation runs infinitely.
How cool is that? It works like a charm. By applying multiple CSS animation
@keyframes to the same element, we get the benefit of the loading indicator while also getting - what I'm told is - a perceived performance improvement by not showing the loading indicator during a sub-second loading workflow. And, we didn't even need React Suspense!