Hourglass Loader

A loading animation that can be wrapped around the container an element is loaded into, so that it sort of "transforms into" the loaded element when its done. Also works as an overlay that reveals the loaded element within from the inside out.

Project Description

I had the idea for this CSS experiment when I was contemplating how to visualize the loading animation for the gallery slider that was in development for this web site's portfolio page. The result is this neat little HTML construct that uses transitions, transformations and a little keyframe animation to display a block of markup as a spinning hourglass icon while its content is still loading. When a CSS class gets removed from that container via JavaScript, it smoothly transforms into a content block (or reveals one when used as an overlay). After completion I immediately integrated it into the coding pages as well, as you can test right below this text by clicking the live demo button. The demo block uses the overlay variant while the demo is loaded and the demo itself shows the wrapper variant.

Used Technologies:

CSS3, HTML, jQuery

Project Files:

  • Full Demo (Zip)

    All components of the demo you can view here, just slightly modified so it can work without external dependencies.

  • CSS file

    If you are only interested in the core functionality, the CSS file alone is sufficient enough.

Inmplementation and Usage

This HTML element can be used in two ways: As a wrapper around the content to be loaded (as per its original conception) and as an overlay in front of the content that should be revealed after it loaded completely.

The markup for that looks as follows:

Usage as a wrapper

<div class="hourglass-loader-wrapper loading">
  <div class="hourglass-loader">
    <div class="hourglass-loader-outer">
      <div class="hourglass-loader-inner">
        <div class="hourglass-loader-content">
          <img alt="Demo Image" src="example.png" />
        </div>
      </div>
    </div>
  </div>
</div>
Within ".hourglass-loader-content" you can insert any kind of content, but it is especially recommended for images.

Usage as an overlay

<div class="example-container contains-hourglass-loader-overlay">
  <div class="hourglass-loader-wrapper overlay loading">
    <div class="hourglass-loader">
      <div class="hourglass-loader-outer">
        <div class="hourglass-loader-inner">
          <div class="hourglass-loader-content"></div>
        </div>
      </div>
    </div>
  </div>
  <div class="example-content"></div>
</div>
Make sure that the container you add the element to has relative positioning and that it has "overflow" set to "hidden". The overlay's z-index must also be higher than that of the other content located inside the container.

Once you have added the markup, apply whatever scripting you use to load the content hidden behind/inside it and when the loading has finished, remove the class "loading" from the block with the class "hourglass-loader-wrapper" to reveal it.

Please note that if your loaded content contains elements that need to be rendered outside the bounds of the container and you are not using it as an overlay, you will have to add the class "finished" to the element you removed the "loading" class from to enable this. But don't do that at the same time you remove the "loading" class, the CSS transition has to finish first (by default it takes ~800 milliseconds in wrapper mode and ~1200 in overlay mode). So it is necessary to use either a timeout or a combination of an event listener for the animation's end and a follow-up timeout (just listening to the event without a timeout will cancel it too soon, as the various elements inside animate at different speeds and once the first one has finished, the event is triggred).

Here's some example code using jQuery:

Applying the "finished" class at the end of the animation

$('.hourglass-loader-wrapper.loading')
 .removeClass('loading')
 .one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(e) {
    var $el = $(this).unbind(); // Unbinding prevents the event from firing twice
    setTimeout(function(){ 
      $el.addClass('finished'); 
    }, 800); 
  });

You should also be aware that a similar problem exists when using overlay mode. Once the animation has finished, the overlay is no longer visible but still present and will thus block interactions with the element that has just been revealed. So the same technique as above must be applied to hide the overlay once its animation is finished. The class name to be applied for that is "revealed":

Hiding the overlay when the animation has ended

$('.hourglass-loader-wrapper.overlay.loading')
 .removeClass('loading')
 .one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(e) {
    var $el = $(this).unbind();
    setTimeout(function(){ 
      $el.addClass('revealed'); // For browser without CSS pointer events support use $el.hide(); instead. Or $el.remove() if it is no longer needed.
    }, 1200); 
  });

The "revealed" class sets to "pointer-events" property to "none". Not all browsers can handle this properly. So if you want to support older and exotic browsers it might be better to hide the element with "display:none" or to delete it completely. If you're hiding it because yyou're planning to re-activate it later, but with an inverted animation, you will have to put a delay in between the operation that displays it again and the one that re-applies the "loading" class, because initially hidden elements will not animate when they are being revealed. So a timeout is needed here as well:

Inverting the overlay reveal animation

$('.hourglass-loader-wrapper.overlay.revealed').show();
setTimeout(function(){
  $('.hourglass-loader-wrapper.overlay.revealed').removeClass('loading').one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(e) {
    var $el = $(this).unbind();
    setTimeout(function(){ 
      $el.hide(); 
    }, 1200); 
  });
}, 240);

The animation speed can be reduced by applying an additional class to the element with the class "hourglass-loader-wrapper". The class "medium-anim" doubles the default duration, the class "slow-anim" quadruples it.