Hourglass Loader

Eine Ladeanimation, welche um das zu ladende Element herum gebaut werden kann, wodurch sich dieses dann quasi in dieses Element "verwandelt" sobald es geladen wurde. Funktioniert alternativ aber auch als Overlay, das dann den Inhalt von innen nach außen frei gibt.

Projekt­beschreibung

Die Idee für dieses CSS-Experiment kam mir, als ich überlegte, wie ich das dynamische Nachladen von Bildern für das sich für den Portfolio-Bereich dieser Website in Entwicklung befindliche Galerie-Plugin am besten visuell aufbereiten könnte. Das Resultat ist dieses nette HTML-Konstrukt, welches mittels Transitionen und Transformationen einen Markup-Block als eine Sanduhr darstellt, solange dessen Inhalt noch lädt. Nach dem Entfernen einer CSS-Klasse via JavaScript verwandelt sich diese dann in einen Inhaltsblock (oder gibt im Overlay-Modus die Sicht auf den inhalt frei). Ich habe dieses Konstrukt direkt nach Fertigstellung auch auf den Coding-Seiten eingesetzt, es erscheint immer wenn ein Live-Demo-kasten geöffnet wird, wie Sie direkt unter diesem Text ausprobieren können. Der Demoblock öffnet sich mit der Overlay-Animation, die Demo darin demonstriert dagegen das Wrapper-Verhalten.

Eingesetzte Technologien:

CSS3, HTML, jQuery

Projekt­dateien:

  • Vollständige Demo (Zip)

    Alle Komponenten der hier einsehbaren Demo-Datei, leicht angepasst um ohne externe Abhängigkeiten laufen zu können.

  • CSS-Datei

    Wenn Sie nur an der Kernfunktionalität interessiert sind, reicht die CSS-Datei vollkommen aus.

Implementierung und Nutzung

Dieses HTML-Element kann auf zwei Arten verwendet werden: Als Wrapper um den zu ladenden Inhalt herum, wie ursprünglich vorgesehen, sowie als ein Overlay welches über dem zu ladenden Inhalt liegt und diesen dann aufdeckt.

Das Markup dazu sieht aus wie folgt:

Benutzung als 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>
Innerhalb von ".hourglass-loader-content" kann man beliebigen Inhalt einfügen, es empfehlen sich aber besonders Bilder.

Benutzung als 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>
Stellen Sie sicher, dass der Container, welcher das Element aufnehmen soll, relativ positioniert ist und unbedingt "overflow" auf "hidden" gesetzt haben muss. Und der Z-Index des Overlay-Elements muss auch höher sein als der der anderen Elemente in dem Container.

Sobald das Markup angelegt wurde, fügen Sie das nötige Scripting hinzu welches den entsprechenden Inhalt lädt und entfernen Sie dann, sobald dieser geladen wurde, die Klasse "loading" von dem Element mit der Klasse "hourglass-loader-wrapper".

Bitte beachten Sie dabei, dass am Ende der Animation im Wrapper-Modus noch eine nachträgliche Operation nötig wird, wenn Sie planen, dass einige der geladenen Elemente aus der Begrenzung des ursprünglichen Inhaltsblocks ausbrechen müssen. Das liegt daran, dass da einige Elemente des Wrappers "overflow: hidden" gesetzt haben. Dazu muss die Klasse "finished" an das Element gehängt werden von dem zuvor die Klasse "loading" entfernt wurde. Dies darf jedoch nicht im selben Moment wie das Entfernen der "loading"-Klasse erfolgen, die Animation muss zuerst zuende ablaufen (was standardmäßig ca. 800 ms im Wrapper-Modus und ca. 1200 ms im Overlay-Modus dauert). Dies kann man entweder über einen Timeout steuern, dessen Länge der vollen Animationsdauer entspricht, oder über eine Kombination aus Event Listener für das Ende der Animation und einem daran gekoppelten Timeout. Ein Event Listener allein reicht nicht aus, da einzelne Unterkomponenten unterschiedlich schnell und teilweise mit Verzögerung ihre Animation abspulen und bereits das erste Element, welches mit seiner Animation durch ist, das Event auslöst.

Hier ein Beispiel mit jQuery:

Setzen der "finished"-Klasse am Ende der 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); 
  });

Ein ähnliches Problem tritt auch bei der Nutzung als Overlay auf. Sobald die Animation beendet ist ist der aufgedeckte Inhalt zwar sichtbar, aber man kann damit nicht interagieren, da das nun unsichtbare Overlay immer noch davor platziert ist und somit Klicks blockiert. Daher muss auch hier die gleiche Technik wie oben angewandt werden um das Element nach dem Ende der Animation zu verbergen, nur dass der Klassenname hier ein anderer ist, nämlich "revealed":

Verbergen des Overlays am Ende der Animation

$('.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); 
  });

Die "revealed"-Klasse setzt für das Overlay "pointer-events:none". Nicht alle Browser können damit vernünftig umgehen. Wenn sie ältere Browser unterstützen möchten, sollten Sie stattdessen das Overlay-Element verstecken oder komplett entfernen. Planan Sie, das Element später wieder anzuzeigen, mit invertierter Animation, dann muss zwischen dem Anzeigen des versteckten Elements und dem hinzufügen der "loading"-Klasse ein wenig Zeit vergehen, denn mit "display:none" ausgeblendete Elemente spulen beim Aktivieren der Sichtbarkeit ihre Animation nicht ab. Diese greift nur, wenn das Element zu Beginn der Animation sichtbar ist, daher muss man zwischen Aufdecken und Animieren einen Timeout einsetzen:

Umkehr der Overlay-Anzeige-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);

Die Geschwindigkeit der Animation kann über eine zusätzliche Klasse am Element mit der Klasse "hourglass-loader-wrapper" gedrosselt werden. Mit der Klasse "medium-anim" verdoppelt sich die Standard-Animationsdauer und mit "slow-anim" ist diese gar vervierfacht.