Verbesserung des Benutzerflusses durch Seitenübergänge

Veröffentlicht: 2022-03-10
Kurze Zusammenfassung ↬ Jedes Mal, wenn die Erfahrung eines Benutzers unterbrochen wird, steigt die Wahrscheinlichkeit, dass er die Seite verlässt. Der Wechsel von einer Seite zur anderen verursacht diese Unterbrechung oft, indem ein weißer Blitz ohne Inhalt angezeigt wird, das Laden zu lange dauert oder der Benutzer auf andere Weise aus dem Kontext gerissen wird, in dem er sich vor dem Öffnen der neuen Seite befand.

Übergänge zwischen Seiten können das Erlebnis verbessern, indem sie den Kontext des Benutzers beibehalten (oder sogar verbessern), seine Aufmerksamkeit aufrechterhalten und visuelle Kontinuität und positives Feedback bieten. Gleichzeitig können Seitenübergänge auch ästhetisch ansprechend und unterhaltsam sein und das Branding stärken, wenn sie gut gemacht sind.

Page Transitions

In diesem Artikel erstellen wir Schritt für Schritt einen Übergang zwischen Seiten. Wir werden auch über die Vor- und Nachteile dieser Technik sprechen und wie man sie an ihre Grenzen bringt.

Beispiele

Viele mobile Apps nutzen Übergänge zwischen Ansichten. Im folgenden Beispiel, das den Material Design-Richtlinien von Google folgt, sehen wir, wie die Animation hierarchische und räumliche Beziehungen zwischen Seiten vermittelt.

Warum verwenden wir bei unseren Websites nicht denselben Ansatz? Warum sind wir damit einverstanden, dass sich der Benutzer jedes Mal teleportiert, wenn sich die Seite ändert?

Mehr nach dem Sprung! Lesen Sie unten weiter ↓

So wechseln Sie zwischen Webseiten

SPA-Frameworks

Bevor wir uns die Hände schmutzig machen, sollte ich etwas über Single-Page-Application (SPA)-Frameworks sagen. Wenn Sie ein SPA-Framework (wie AngularJS, Backbone.js oder Ember) verwenden, wird das Erstellen von Übergängen zwischen Seiten viel einfacher, da das gesamte Routing bereits von JavaScript übernommen wird. Bitte lesen Sie die entsprechende Dokumentation, um zu sehen, wie Sie Seiten mit dem Framework Ihrer Wahl umstellen, da es wahrscheinlich einige gute Beispiele und Tutorials gibt.

Der falsche Weg

Mein erster Versuch, einen Übergang zwischen Seiten zu erstellen, sah ungefähr so ​​aus:

 document.addEventListener('DOMContentLoaded', function() { // Animate in }); document.addEventListener('beforeunload', function() { // Animate out });

Das Konzept ist einfach: Verwenden Sie eine Animation, wenn der Benutzer die Seite verlässt, und eine andere Animation, wenn die neue Seite geladen wird.

Ich stellte jedoch bald fest, dass diese Lösung einige Einschränkungen hatte:

  • Wir wissen nicht, wie lange das Laden der nächsten Seite dauert, daher sieht die Animation möglicherweise nicht flüssig aus.
  • Wir können keine Übergänge erstellen, die Inhalte von der vorherigen und der nächsten Seite kombinieren.

Tatsächlich besteht die einzige Möglichkeit, einen fließenden und reibungslosen Übergang zu erreichen, darin, die volle Kontrolle über den Seitenwechselprozess zu haben und daher die Seite überhaupt nicht zu wechseln . Daher müssen wir unsere Herangehensweise an das Problem ändern.

Der richtige Weg

Schauen wir uns die Schritte an, die erforderlich sind, um einen einfachen Crossfade-Übergang zwischen Seiten richtig zu erstellen. Es handelt sich um eine sogenannte pushState AJAX (oder PJAX) Navigation, die unsere Website im Wesentlichen in eine Art Single-Page-Website verwandeln wird.

Diese Technik erzielt nicht nur glatte und angenehme Übergänge, sondern wir profitieren von weiteren Vorteilen, auf die wir später in diesem Artikel ausführlich eingehen werden.

Verhindern Sie das standardmäßige Verbindungsverhalten

Der erste Schritt besteht darin, einen click Event-Listener für alle zu verwendenden Links zu erstellen, um zu verhindern, dass der Browser sein Standardverhalten ausführt, und um die Art und Weise anzupassen, wie er Seitenänderungen handhabt.

 // Note, we are purposely binding our listener on the document object // so that we can intercept any anchors added in future. document.addEventListener('click', function(e) { var el = e.target; // Go up in the nodelist until we find a node with .href (HTMLAnchorElement) while (el && !el.href) { el = el.parentNode; } if (el) { e.preventDefault(); return; } });

Diese Methode zum Hinzufügen eines Ereignis-Listeners zu einem übergeordneten Element, anstatt ihn zu jedem bestimmten Knoten hinzuzufügen, wird als Ereignisdelegierung bezeichnet und ist aufgrund der Ereignis-Bubbling-Natur der HTML-DOM-API möglich.

Holen Sie sich die Seite

Nachdem wir den Browser unterbrochen haben, wenn er versucht, die Seite zu ändern, können wir diese Seite mithilfe der Fetch-API manuell abrufen. Schauen wir uns die folgende Funktion an, die den HTML-Inhalt einer Seite abruft, wenn ihre URL angegeben wird.

 function loadPage(url) { return fetch(url, { method: 'GET' }).then(function(response) { return response.text(); }); }

Bei Browsern, die die Fetch-API nicht unterstützen, sollten Sie das Polyfill hinzufügen oder das gute altmodische XMLHttpRequest verwenden.

Ändern Sie die aktuelle URL

HTML5 hat eine fantastische API namens pushState , die es Websites ermöglicht, auf den Verlauf des Browsers zuzugreifen und ihn zu ändern, ohne Seiten zu laden. Unten verwenden wir es, um die aktuelle URL in die URL der nächsten Seite zu ändern. Beachten Sie, dass dies eine Modifikation unseres zuvor deklarierten Anker-Click-Event-Handlers ist.

 if (el) { e.preventDefault(); history.pushState(null, null, el.href); changePage(); return; }

Wie Sie vielleicht bemerkt haben, haben wir auch einen Aufruf zu einer Funktion mit dem Namen changePage , auf die wir uns in Kürze im Detail ansehen werden. Dieselbe Funktion wird auch im popstate Ereignis aufgerufen, das ausgelöst wird, wenn sich der aktive Verlaufseintrag des Browsers ändert (wie wenn ein Benutzer auf die Schaltfläche „Zurück“ seines Browsers klickt):

 window.addEventListener('popstate', changePage);

Mit all dem bauen wir im Grunde genommen ein sehr primitives Routing-System auf, in dem wir aktive und passive Modi haben.

Unser aktiver Modus wird verwendet, wenn ein Benutzer auf einen Link klickt und wir die URL mit pushState , während der passive Modus verwendet wird, wenn sich die URL ändert und wir vom popstate Ereignis benachrichtigt werden. In beiden Fällen rufen wir changePage auf, das sich um das Lesen der neuen URL und das Laden der relevanten Seite kümmert.

Analysieren und fügen Sie den neuen Inhalt hinzu

In der Regel haben die Seiten, auf denen navigiert wird, gemeinsame Elemente wie header und footer . Angenommen, wir verwenden die folgende DOM-Struktur auf allen unseren Seiten (die eigentlich die Struktur von Smashing Magazine selbst ist):

Animieren!

Wenn der Benutzer auf einen Link klickt, ruft die Funktion changePage den HTML- Code dieser Seite ab, extrahiert dann den cc -Container und fügt ihn dem main hinzu. An diesem Punkt haben wir zwei cc -Container auf unserer Seite, der erste gehört zur vorherigen Seite und der zweite von der nächsten Seite.

Die nächste Funktion, animate , kümmert sich um die Überblendung der beiden Container, indem sie diese überlappt, den alten ausblendet, den neuen einblendet und den alten Container entfernt. In diesem Beispiel verwende ich die Webanimations-API, um die Fade-Animation zu erstellen, aber natürlich können Sie jede Technik oder Bibliothek verwenden, die Sie möchten.

 function animate(oldContent, newContent) { oldContent.style.position = 'absolute'; var fadeOut = oldContent.animate({ opacity: [1, 0] }, 1000); var fadeIn = newContent.animate({ opacity: [0, 1] }, 1000); fadeIn.onfinish = function() { oldContent.parentNode.removeChild(oldContent); }; }

Der endgültige Code ist auf GitHub verfügbar.

Und das sind die Grundlagen für den Übergang von Webseiten!

Vorbehalte und Einschränkungen

Das kleine Beispiel, das wir gerade erstellt haben, ist alles andere als perfekt. Tatsächlich haben wir ein paar Dinge noch nicht berücksichtigt:

  • Stellen Sie sicher, dass wir die richtigen Links beeinflussen.
    Bevor wir das Verhalten eines Links ändern, sollten wir eine Überprüfung hinzufügen, um sicherzustellen, dass es geändert werden sollte. Zum Beispiel sollten wir alle Links mit target="_blank" (wodurch die Seite in einem neuen Tab geöffnet wird), alle Links zu externen Domains und einige andere Sonderfälle wie Control/Command + click (wodurch die Seite auch in geöffnet wird eine neue Registerkarte).
  • Aktualisieren Sie Elemente außerhalb des Hauptinhaltscontainers.
    Wenn sich die Seite derzeit ändert, bleiben alle Elemente außerhalb des cc -Containers gleich. Einige dieser Elemente müssten jedoch geändert werden (was jetzt nur manuell möglich wäre), darunter der title des Dokuments, das Menüelement mit der active Klasse und je nach Website möglicherweise viele andere.
  • Verwalten Sie den Lebenszyklus von JavaScript.
    Unsere Seite verhält sich nun wie ein SPA, bei dem der Browser nicht selbst Seiten wechselt. Wir müssen uns also manuell um den JavaScript-Lebenszyklus kümmern – zum Beispiel bestimmte Ereignisse binden und entbinden, Plugins neu bewerten und Polyfills und Code von Drittanbietern einbeziehen.

Browser-Unterstützung

Die einzige Voraussetzung für diesen Navigationsmodus, den wir implementieren, ist die pushState API, die in allen modernen Browsern verfügbar ist. Diese Technik funktioniert vollständig als progressive Verbesserung . Die Seiten werden weiterhin auf die übliche Weise bereitgestellt und sind zugänglich, und die Website funktioniert weiterhin normal, wenn JavaScript deaktiviert ist.

Wenn Sie ein SPA-Framework verwenden, sollten Sie stattdessen die PJAX-Navigation verwenden, um die Navigation schnell zu halten. Auf diese Weise erhalten Sie Legacy-Unterstützung und erstellen eine SEO-freundlichere Website.

Noch weiter gehen

Wir können die Grenzen dieser Technik weiter verschieben, indem wir bestimmte Aspekte davon optimieren. Die nächsten paar Tricks werden die Navigation beschleunigen und die Erfahrung des Benutzers erheblich verbessern.

Verwenden eines Caches

Durch eine leichte Änderung unserer loadPage Funktion können wir einen einfachen Cache hinzufügen, der dafür sorgt, dass bereits besuchte Seiten nicht neu geladen werden.

 var cache = {}; function loadPage(url) { if (cache[url]) { return new Promise(function(resolve) { resolve(cache[url]); }); } return fetch(url, { method: 'GET' }).then(function(response) { cache[url] = response.text(); return cache[url]; }); }

Wie Sie vielleicht erraten haben, können wir einen dauerhafteren Cache mit der Cache-API oder einen anderen Client-seitigen persistenten Speicher-Cache (wie IndexedDB) verwenden.

Animieren der aktuellen Seite

Unser Crossfade-Effekt erfordert, dass die nächste Seite geladen und bereit ist, bevor der Übergang abgeschlossen ist. Mit einem anderen Effekt möchten wir vielleicht damit beginnen, die alte Seite zu animieren, sobald der Benutzer auf den Link klickt, was dem Benutzer sofortiges Feedback geben würde, was eine große Hilfe für die wahrgenommene Leistung ist.

Durch die Verwendung von Versprechungen wird der Umgang mit dieser Art von Situation sehr einfach. Die Methode .all erstellt ein neues Promise, das aufgelöst wird, sobald alle als Argumente enthaltenen Promises aufgelöst sind.

 // As soon as animateOut() and loadPage() are resolved… Promise.all[animateOut(), loadPage(url)] .then(function(values) { …

Vorabruf der nächsten Seite

Wenn Sie nur die PJAX-Navigation verwenden, sind Seitenwechsel normalerweise fast doppelt so schnell wie bei der Standardnavigation, da der Browser keine Skripte oder Stile auf der neuen Seite parsen und auswerten muss.

Wir können jedoch noch weiter gehen, indem wir beginnen, die nächste Seite vorab zu laden, wenn der Benutzer den Mauszeiger über den Link bewegt oder anfängt, ihn zu berühren.

Wie Sie sehen können, gibt es normalerweise eine Verzögerung von 200 bis 300 Millisekunden beim Bewegen und Klicken des Benutzers. Dies ist Totzeit und reicht in der Regel aus, um die nächste Seite zu laden.

Allerdings sollten Sie mit Bedacht vorabrufen, da dies leicht zu einem Engpass werden kann. Wenn Sie beispielsweise eine lange Liste mit Links haben und der Benutzer sie durchscrollt, werden mit dieser Technik alle Seiten vorab abgerufen, da die Links unter der Maus hindurchgehen.

Ein weiterer Faktor, den wir bei der Entscheidung über den Prefetch erkennen und berücksichtigen könnten, ist die Verbindungsgeschwindigkeit des Benutzers. (Vielleicht wird dies in Zukunft mit der Network Information API möglich.)

Teilausgabe

In unserer loadPage Funktion holen wir das gesamte HTML-Dokument, aber eigentlich brauchen wir nur den cc -Container. Wenn wir eine serverseitige Sprache verwenden, können wir erkennen, ob die Anfrage von einem bestimmten benutzerdefinierten AJAX-Aufruf stammt, und in diesem Fall nur den benötigten Container ausgeben. Durch die Verwendung der Header-API können wir einen benutzerdefinierten HTTP-Header in unserer Abrufanforderung senden.

 function loadPage(url) { var myHeaders = new Headers(); myHeaders.append('x-pjax', 'yes'); return fetch(url, { method: 'GET', headers: myHeaders, }).then(function(response) { return response.text(); }); }

Dann können wir auf der Serverseite (in diesem Fall mit PHP) erkennen, ob unser benutzerdefinierter Header vorhanden ist, bevor nur der erforderliche Container ausgegeben wird:

 if (isset($_SERVER['HTTP_X_PJAX'])) { // Output just the container }

Dadurch wird die Größe der HTTP-Nachricht reduziert und auch die serverseitige Last reduziert.

Einpacken

Nachdem ich diese Technik in einigen Projekten implementiert hatte, wurde mir klar, dass eine wiederverwendbare Bibliothek immens hilfreich wäre. Es würde mir Zeit sparen, es bei jeder Gelegenheit zu implementieren, und mich auf die Übergangseffekte selbst konzentrieren.

So wurde Barba.js geboren, eine winzige Bibliothek (4 KB verkleinert und gZip), die all diese Komplexität abstrahiert und eine schöne, saubere und einfache API für Entwickler zur Verfügung stellt. Es berücksichtigt auch Ansichten und kommt mit wiederverwendbaren Übergängen, Caching, Prefetching und Events. Es ist Open Source und auf GitHub verfügbar.

Fazit

Wir haben jetzt gesehen, wie man einen Crossfade-Effekt erzeugt und die Vor- und Nachteile der Verwendung der PJAX-Navigation, um unsere Website effektiv in ein SPA zu verwandeln. Abgesehen von den Vorteilen des Übergangs selbst haben wir auch gesehen, wie einfache Caching- und Prefetching-Mechanismen implementiert werden können, um das Laden neuer Seiten zu beschleunigen.

Dieser gesamte Artikel basiert auf meinen persönlichen Erfahrungen und dem, was ich bei der Implementierung von Seitenübergängen in Projekten gelernt habe, an denen ich gearbeitet habe. Wenn Sie Fragen haben, zögern Sie nicht, einen Kommentar zu hinterlassen oder mich auf Twitter zu kontaktieren – meine Informationen finden Sie unten!

Weiterführende Literatur zu SmashingMag:

  • Intelligente Übergänge im User Experience Design
  • Design im Übergang zu einer Multi-Device-Welt
  • Bereitstellung einer nativen Erfahrung mit Webtechnologien