AJAX loading spinner without flickering artifacts

We were embedding a spinner to give user feedback while loading data from a server which might take a little longer (but can also be pretty quick in most cases).

Implementing the spinner itself isn’t that hard, but we found that quick responses from the server caused visual artifacts flickering up because the spinner was only visible for a few milliseconds (probably roughly 30ms).

The solution we chose to implement looks like this:

  • before triggering the AJAX request, schedule the code that loads the spinner 150ms into the future
  • if the AJAX request returns and the spinner did not materialize yet, cancel the scheduled code
  • if the AJAX request returns and the spinner was materialized, schedule the code to hide the spinner 200ms into the future

We also had two smaller variations:

  • if the replacement looks almost identical to what was shown before, don’t hide it until the spinner actually shows up.
  • if the replacement looks usually a lot different, then blank the area immediately waiting for the spinner to show up or not.

We implemented this with MochiKit and here is some sample code:

var expansion_element = $('mydivcontainingstuff');
var spinner_loader = MochiKit.Async.callLater(0.15, function() {
   MochiKit.DOM.addElementClass(expansion_element, 'loading');
   MochiKit.DOM.addElementClass(expansion_element, 'loading-spinner');
   spinner_loader = null;
d = MochiKit.Async.doSimpleXMLHttpRequest(ajax_url);
   $('mystuffdivcontainingstuff').innerHTML = result.responseText;

   if (spinner_loader != null ) {
   } else {
       MochiKit.Async.callLater(0.2, function() {
       MochiKit.DOM.removeElementClass(expansion_element, 'loading-spinner');
       MochiKit.DOM.removeElementClass(expansion_element, 'loading');

And here’s the CSS:

.loading-spinner {
  width: 100px;
  height: 100px;
  margin-left: auto !important;
  margin-right: auto !important;
  background-image: url(ajax-loader.gif);
  background-repeat: no-repeat;
  background-position: 50% 50%;

.loading * {
  display: none;

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: