Amélioration du flux d'utilisateurs à travers les transitions de page

Publié: 2022-03-10
Résumé rapide ↬ Chaque fois que l'expérience d'un utilisateur est interrompue, les chances qu'il parte augmentent. Le passage d'une page à une autre provoque souvent cette interruption en affichant un flash blanc sans contenu, en prenant trop de temps à charger ou en sortant l'utilisateur du contexte dans lequel il se trouvait avant l'ouverture de la nouvelle page.

Les transitions entre les pages peuvent améliorer l'expérience en conservant (ou même en améliorant) le contexte de l'utilisateur, en maintenant son attention et en offrant une continuité visuelle et un retour positif. Dans le même temps, les transitions de page peuvent également être esthétiques et amusantes et peuvent renforcer l'image de marque lorsqu'elles sont bien faites.

Page Transitions

Dans cet article, nous allons créer, étape par étape, une transition entre les pages. Nous aborderons également les avantages et les inconvénients de cette technique et comment la pousser jusqu'à ses limites.

Exemples

De nombreuses applications mobiles font bon usage des transitions entre les vues. Dans l'exemple ci-dessous, qui suit les directives de conception matérielle de Google, nous voyons comment l'animation transmet des relations hiérarchiques et spatiales entre les pages.

Pourquoi n'utilisons-nous pas la même approche avec nos sites Web ? Pourquoi acceptons-nous que l'utilisateur ait l'impression d'être téléporté à chaque fois que la page change ?

Plus après saut! Continuez à lire ci-dessous ↓

Comment faire la transition entre les pages Web

Cadres SPA

Avant de nous salir les mains, je dois dire quelque chose sur les frameworks d'application monopage (SPA). Si vous utilisez un framework SPA (tel que AngularJS, Backbone.js ou Ember), la création de transitions entre les pages sera beaucoup plus facile car tout le routage est déjà géré par JavaScript. Veuillez vous référer à la documentation pertinente pour voir comment effectuer la transition des pages en utilisant le cadre de votre choix, car il existe probablement de bons exemples et des didacticiels.

La mauvaise direction

Ma première tentative pour créer une transition entre les pages ressemblait plus ou moins à ceci :

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

Le concept est simple : utilisez une animation lorsque l'utilisateur quitte la page et une autre animation lorsque la nouvelle page se charge.

Cependant, j'ai vite constaté que cette solution avait quelques limites :

  • Nous ne savons pas combien de temps la page suivante prendra pour se charger, donc l'animation peut ne pas sembler fluide.
  • Nous ne pouvons pas créer de transitions qui combinent le contenu des pages précédentes et suivantes.

En fait, la seule façon d'obtenir une transition fluide et fluide est d'avoir un contrôle total sur le processus de changement de page et, par conséquent, de ne pas changer la page du tout . Ainsi, nous devons changer notre approche du problème.

Le droit chemin

Regardons les étapes impliquées dans la création d'une simple transition de fondu enchaîné entre les pages de la bonne manière. Cela implique quelque chose appelé pushState AJAX (ou PJAX), qui transformera essentiellement notre site Web en une sorte de site Web d'une seule page.

Non seulement cette technique permet d'obtenir des transitions douces et agréables, mais nous bénéficierons d'autres avantages, que nous aborderons en détail plus loin dans cet article.

Empêcher le comportement de lien par défaut

La première étape consiste à créer un écouteur d'événement de click pour tous les liens à utiliser, empêchant le navigateur d'exécuter son comportement par défaut et personnalisant la façon dont il gère les changements de page.

 // 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; } });

Cette méthode d'ajout d'un écouteur d'événement à un élément parent, au lieu de l'ajouter à chaque nœud spécifique, est appelée délégation d'événement, et c'est possible en raison de la nature bouillonnante d'événements de l'API HTML DOM.

Récupérer la page

Maintenant que nous avons interrompu le navigateur lorsqu'il essaie de changer de page, nous pouvons récupérer manuellement cette page à l'aide de l'API Fetch. Regardons la fonction suivante, qui récupère le contenu HTML d'une page lorsqu'on lui donne son URL.

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

Pour les navigateurs qui ne prennent pas en charge l'API Fetch, pensez à ajouter le polyfill ou à utiliser le bon vieux XMLHttpRequest .

Modifier l'URL actuelle

HTML5 possède une API fantastique appelée pushState , qui permet aux sites Web d'accéder à l'historique du navigateur et de le modifier sans charger aucune page. Ci-dessous, nous l'utilisons pour modifier l'URL actuelle afin qu'elle devienne l'URL de la page suivante. Notez qu'il s'agit d'une modification de notre gestionnaire d'événement de clic d'ancrage précédemment déclaré.

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

Comme vous l'avez peut-être remarqué, nous avons également ajouté un appel à une fonction nommée changePage , que nous examinerons en détail sous peu. La même fonction sera également appelée dans l'événement popstate , qui est déclenché lorsque l'entrée d'historique active du navigateur change (comme lorsqu'un utilisateur clique sur le bouton de retour de son navigateur) :

 window.addEventListener('popstate', changePage);

Avec tout cela, nous construisons essentiellement un système de routage très primitif, dans lequel nous avons des modes actifs et passifs.

Notre mode actif est utilisé lorsqu'un utilisateur clique sur un lien et que nous modifions l'URL à l'aide pushState , tandis que le mode passif est utilisé lorsque l'URL change et que nous sommes avertis par l'événement popstate . Dans les deux cas, nous allons appeler changePage , qui se charge de lire la nouvelle URL et de charger la page concernée.

Analyser et ajouter le nouveau contenu

En règle générale, les pages parcourues auront des éléments communs, comme header et footer . Supposons que nous utilisions la structure DOM suivante sur toutes nos pages (qui est en fait la structure de Smashing Magazine lui-même) :

Animer!

Lorsque l'utilisateur clique sur un lien, la fonction changePage récupère le code HTML de cette page, puis extrait le conteneur cc et l' ajoute à l'élément main . À ce stade, nous avons deux conteneurs cc sur notre page, le premier appartenant à la page précédente et le second à la page suivante.

La fonction suivante, animate , s'occupe de fondre les deux conteneurs en les superposant, en faisant disparaître l'ancien, en faisant apparaître le nouveau et en supprimant l'ancien conteneur. Dans cet exemple, j'utilise l'API Web Animations pour créer l'animation de fondu, mais bien sûr, vous pouvez utiliser n'importe quelle technique ou bibliothèque que vous souhaitez.

 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); }; }

Le code final est disponible sur GitHub.

Et ce sont les bases de la transition des pages Web !

Mises en garde et limites

Le petit exemple que nous venons de créer est loin d'être parfait. En fait, nous n'avons toujours pas pris en compte certaines choses :

  • Assurez-vous que nous affectons les liens corrects.
    Avant de modifier le comportement d'un lien, nous devons ajouter une vérification pour nous assurer qu'il doit être modifié. Par exemple, nous devrions ignorer tous les liens avec target="_blank" (qui ouvre la page dans un nouvel onglet), tous les liens vers des domaines externes et certains autres cas particuliers, comme Control/Command + click (qui ouvre également la page dans un nouvel onglet).
  • Mettez à jour les éléments en dehors du conteneur de contenu principal.
    Actuellement, lorsque la page change, tous les éléments en dehors du conteneur cc restent les mêmes. Cependant, certains de ces éléments devraient être modifiés (ce qui ne pouvait désormais être fait que manuellement), notamment le title du document, l'élément de menu avec la classe active , et potentiellement de nombreux autres selon le site Web.
  • Gérez le cycle de vie de JavaScript.
    Notre page se comporte désormais comme un SPA, dans lequel le navigateur ne modifie pas lui-même les pages. Nous devons donc nous occuper manuellement du cycle de vie JavaScript - par exemple, lier et dissocier certains événements, réévaluer les plugins et inclure des polyfills et du code tiers.

Prise en charge du navigateur

La seule exigence pour ce mode de navigation que nous implémentons est l'API pushState , qui est disponible dans tous les navigateurs modernes. Cette technique fonctionne pleinement comme une amélioration progressive . Les pages sont toujours servies et accessibles de la manière habituelle, et le site Web continuera à fonctionner normalement lorsque JavaScript est désactivé.

Si vous utilisez un framework SPA, envisagez plutôt d'utiliser la navigation PJAX, juste pour que la navigation reste rapide. Ce faisant, vous bénéficiez d'un support hérité et créez un site Web plus convivial pour le référencement.

Aller encore plus loin

Nous pouvons continuer à repousser les limites de cette technique en optimisant certains aspects de celle-ci. Les quelques astuces suivantes accéléreront la navigation, améliorant considérablement l'expérience de l'utilisateur.

Utilisation d'un cache

En modifiant légèrement notre fonction loadPage , nous pouvons ajouter un cache simple, qui s'assure que les pages déjà visitées ne sont pas rechargées.

 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]; }); }

Comme vous l'avez peut-être deviné, nous pouvons utiliser un cache plus permanent avec l'API Cache ou un autre cache de stockage persistant côté client (comme IndexedDB).

Animation de la page actuelle

Notre effet de fondu enchaîné nécessite que la page suivante soit chargée et prête avant la fin de la transition. Avec un autre effet, nous pourrions vouloir commencer à animer l'ancienne page dès que l'utilisateur clique sur le lien, ce qui donnerait à l'utilisateur un retour immédiat, une aide précieuse pour la performance perçue.

En utilisant des promesses, gérer ce genre de situation devient très facile. La méthode .all crée une nouvelle promesse qui est résolue dès que toutes les promesses incluses en tant qu'arguments sont résolues.

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

Préchargement de la page suivante

En utilisant uniquement la navigation PJAX, les changements de page sont généralement presque deux fois plus rapides que la navigation par défaut, car le navigateur n'a pas à analyser et à évaluer les scripts ou les styles sur la nouvelle page.

Cependant, nous pouvons aller encore plus loin en commençant à précharger la page suivante lorsque l'utilisateur survole ou commence à toucher le lien.

Comme vous pouvez le voir, il y a généralement 200 à 300 millisecondes de retard dans le survol et le clic de l'utilisateur. C'est un temps mort et c'est généralement suffisant pour charger la page suivante.

Cela étant dit, préchargez judicieusement car cela peut facilement devenir un goulot d'étranglement. Par exemple, si vous avez une longue liste de liens et que l'utilisateur la fait défiler, cette technique prélèvera toutes les pages car les liens passent sous la souris.

Un autre facteur que nous pourrions détecter et prendre en compte pour décider de prérécupérer est la vitesse de connexion de l'utilisateur. (Peut-être que cela sera rendu possible à l'avenir avec l'API Network Information.)

Sortie partielle

Dans notre fonction loadPage , nous récupérons l'intégralité du document HTML, mais nous n'avons en fait besoin que du conteneur cc . Si nous utilisons un langage côté serveur, nous pouvons détecter si la requête provient d'un appel AJAX personnalisé particulier et, si c'est le cas, générer uniquement le conteneur dont il a besoin. En utilisant l'API Headers, nous pouvons envoyer un en-tête HTTP personnalisé dans notre requête de récupération.

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

Ensuite, côté serveur (en utilisant PHP dans ce cas), nous pouvons détecter si notre en-tête personnalisé existe avant de sortir uniquement le conteneur requis :

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

Cela réduira la taille du message HTTP et réduira également la charge côté serveur.

Emballer

Après avoir implémenté cette technique dans quelques projets, j'ai réalisé qu'une bibliothèque réutilisable serait extrêmement utile. Cela me ferait gagner du temps dans sa mise en œuvre à chaque occasion, me permettant de me concentrer sur les effets de transition eux-mêmes.

Ainsi est né Barba.js, une petite bibliothèque (4 Ko minifiée et gZip'd) qui résume toute cette complexité et fournit une API agréable, propre et simple à utiliser pour les développeurs. Il tient également compte des vues et est livré avec des transitions, une mise en cache, une prélecture et des événements réutilisables. Il est open source et disponible sur GitHub.

Conclusion

Nous avons vu maintenant comment créer un effet de fondu enchaîné et les avantages et les inconvénients de l'utilisation de la navigation PJAX pour transformer efficacement notre site Web en SPA. Outre l'avantage de la transition elle-même, nous avons également vu comment mettre en œuvre des mécanismes simples de mise en cache et de prélecture pour accélérer le chargement des nouvelles pages.

Cet article entier est basé sur mon expérience personnelle et sur ce que j'ai appris de la mise en œuvre des transitions de page dans les projets sur lesquels j'ai travaillé. Si vous avez des questions, n'hésitez pas à laisser un commentaire ou à me contacter sur Twitter — mes informations sont ci-dessous !

Lectures complémentaires sur SmashingMag :

  • Transitions intelligentes dans la conception de l'expérience utilisateur
  • Concevoir dans la transition vers un monde multi-appareils
  • Fournir une expérience native avec les technologies Web