Core Web Vitals Google : Cumulative Layout Shift (CLS)

Le Cumulative Layout Shift (CLS) est une métrique centrée utilisateur qui permet d’évaluer la stabilité visuelle d’une page web. Elle permet de mesurer la fréquence à laquelle les utilisateurs subissent des changements de mise en page inattendus. Ainsi, un CLS faible indique que la page est stable et que son utilisation offre une expérience utilisateur de qualité.

Vous avez certainement déjà commencé à lire un article en ligne, et tout à coup, le texte se déplace et vous perdez le fil. Ou pire encore : vous êtes sur le point de cliquer sur un lien ou un bouton, mais à l’instant où vous voulez cliquer, le contenu se déplace et vous cliquez sur autre chose. Ces expériences sont au mieux agaçantes, au pire dommageables - tel qu'on le voit dans cette vidéo :

Illustration de l’impact négatif d’un écran instable sur l’UX (Source Google)

 

Un déplacement inattendu du contenu se produit généralement parce que les ressources sont chargées de manière asynchrone, ou que les éléments DOM sont ajoutés dynamiquement à la page au-dessus du contenu existant. 

Qu’est-ce qui provoque ces mouvements ? Cela peut être une image ou une vidéo aux dimensions inconnues, une font qui s’affiche plus ou moins grande par rapport à la version sans style du texte, ou une publicité ou un widget tiers qui se redimensionnent dynamiquement.

Ces phénomènes ne peuvent malheureusement pas toujours être anticipés en environnement de développement parce que celui-ci est souvent très différent de ce que les utilisateurs perçoivent en production. Le contenu personnalisé ou tiers ne se comporte souvent pas de la même manière entre ces deux environnements, les images de test sont souvent déjà dans le cache du navigateur du développeur et les appels d'API qui s'exécutent localement sont souvent si rapides que le délai n'est pas perceptible. Mais alors, comment faire pour évaluer la perception de stabilité d’une page web ?

Le Cumulative Layout Shift (CLS) permet de répondre à cette problématique en mesurant la fréquence à laquelle des changements se produisent sur l’écran des internautes.

Qu'est-ce que le Cumulative Layout Shift (CLS) ? Définition.

Le CLS mesure la somme totale de tous les scores de changement de mise en page (ou scores de Layout Shift, dont le mode de calcul est expliqué ici), cumulant chaque changement de mise en page inattendu qui se produit pendant toute la durée de vie de la page.

Un changement de mise en page se produit chaque fois qu'un élément visible change de position.

 

Télécharger le dossier Core Web Vitals

Qu'est-ce qu'un bon Cumulative Layout Shift ? 

Pour une bonne expérience utilisateur, le CLS doit être inférieur à 0,1. Pour vous assurer d'atteindre cet objectif pour la plupart de vos utilisateurs, Google recommande de prendre en compte le 75ème centile des temps de chargement des pages, pour les appareils mobiles et desktop

Qu’est-ce qu’un Layout Shift (changement de position) ?

Les Layout Shifts sont définis par Layout Instability API qui signale les occurrences layout-shift à chaque fois qu'un élément visible dans le viewport change par rapport à sa position de départ (par exemple, en haut à gauche dans le mode d'écriture par défaut) entre deux frames rendues. Ces éléments sont alors considérés comme des éléments instables.

Notez que les Layout Shifts ne se produisent que lorsque les éléments existants changent de position de départ. Si un nouvel élément est ajouté au DOM ou qu'un élément existant change de taille, ça ne compte pas comme Layout Shift - tant que ce changement ne modifie pas la position de départ d'autres éléments visibles.

Le score de Layout Shift

Pour calculer le score de Layout Shift, le navigateur examine la taille de la fenêtre et le mouvement des éléments instables dans la fenêtre entre deux frames rendues. Le score de Layout Shift est le produit de deux mesures de ce mouvement : Impact Fraction et Impact Distance (tous deux définis ci-dessous).

layout shift score = impact fraction * distance fraction

Impact Fraction

La mesure Impact Fraction permet d’observer les éléments instables dans le viewport entre deux frames.

Le cumul des zones visibles de tous les éléments instables de la frame précédente et de la frame actuelle, en tant que fraction de la zone totale de la fenêtre, est ce qui s’appelle l’Impact Fraction de la frame actuelle.

Cumulative Layout Shift -cls-Core Web Vitals - Impact Fraction

Dans l'image ci-dessus, on voit un élément qui occupe la moitié de l’écran dans une image. Ensuite, l'élément descend de 25 % par rapport à la taille du viewport. Le rectangle en pointillés rouges indique le cumul de la zone visible de l'élément dans les deux frames, qui, dans ce cas, représente 75 % du viewport. Son Impact Fraction est donc de 0,75.

Distance Fraction

L'autre composante du calcul du score de Layout Shift permet d’évaluer la distance que les éléments instables ont parcourue dans la fenêtre. Distance Fraction est la plus grande distance qu'un élément instable a parcourue dans le cadre (horizontalement ou verticalement) divisée par la plus grande dimension du viewport (largeur ou hauteur, selon la valeur la plus élevée).

Cumulative Layout Shift -cls-Core Web Vitals - Distance Fraction

Dans l'exemple ci-dessus, la plus grande distance parcourue par l'élément instable est un déplacement de maximum de 25 % en hauteur dans la fenêtre. La Distance Fraction est donc de 0,25.

En somme, dans cet exemple, l’Impact Fraction est de 0,75 et la Distance Fraction est de 0,25, ce qui fait que le score de Layout Shift est de 0,75 * 0,25 = 0,1875.

NB : Initialement, le score de Layout Shift était calculé uniquement en fonction de l’Impact Fraction. Distance Fraction a été introduit pour éviter de pénaliser les cas où de gros éléments se déplacent légèrement.

L'exemple suivant illustre comment l'ajout de contenu à un élément existant affecte le score de Layout Shift :

Cumulative Layout Shift -cls-Core Web Vitals - DOM

On voit que le bouton "Click Me!" est ajouté en-dessous du bloc gris avec du texte noir, ce qui pousse le bloc vert avec du texte blanc vers le bas (et partiellement hors de la fenêtre).

Dans cet exemple, la zone grise change de taille, mais sa position de départ ne change pas, ce n'est donc pas un élément instable.

Le bouton "Click Me!" n'était pas dans le DOM au départ, ce qui fait qu’il n’y a pas non plus de changement de position pour cet élément.

La position de départ du bloc vert change cependant, mais comme il a été déplacé partiellement hors de la fenêtre, la zone invisible n'est pas prise en compte lors du calcul de l’Impact Fraction. Le cumul des zones visibles du bloc vert dans les deux frames (illustré par le rectangle rouge en pointillés) est le même que la zone du bloc vert dans la première image, soit 50 % de la fenêtre. L’Impact Fraction est donc de 0,5.

Distance Fraction est illustrée par la flèche violette. Le bloc vert est descendu d'environ 14 % dans la fenêtre, la Distance Fraction est donc de 0,14.

Le score de Layout Shift est de 0,5 x 0,14 = 0,07.

Voyons maintenant ce qui se passe lorsque plusieurs éléments sont instables dans l’exemple ci-dessous :

Cumulative Layout Shift -cls-Core Web Vitals - API Call

Dans la première frame ci-dessus, il y a quatre résultats d'un appel d'API pour différents animaux, triés par ordre alphabétique. Dans la 2ème frame, des résultats sont ajoutés à la liste triée.

Le premier élément de la liste ("Cat") ne change pas sa position de départ entre les images, il est donc stable. Les nouveaux éléments ajoutés à la liste n'étaient pas initialement dans le DOM, donc leur position de départ ne change pas non plus. Mais les éléments "Dog", "Horse" et "Zebra" changent tous leurs positions de départ, ce qui en fait des éléments instables.

Encore une fois, les rectangles rouges en pointillés représentent le cumul de ces trois zones instables avant et après, qui dans ce cas, cela représente environ 38 % du viewport (Fraction Impact = 0,38).

Les flèches représentent les distances que les éléments instables ont parcouru par rapport à leurs positions de départ. "Zebra", représenté par la flèche bleue, a bougé le plus, d'environ 30 % de la hauteur de la fenêtre. Sa Distance Fraction est donc de 0,3.

Le score de Layout Shift pour cet exemple est de 0,38 x 0,3 = 0,1172.

Layout Shifts attendus et inattendus

Notez que tous les changements de disposition ne sont pas mauvais. En effet, de nombreuses applications web dynamiques modifient fréquemment la position initiale des éléments sur une page.

Les Layout Shifts initiés par l'utilisateur 

Un changement de mise en page n'est mauvais que si l'utilisateur ne s'y attend pas. Par ailleurs, les Layout Shifts qui se produisent en réponse aux interactions des utilisateurs (cliquer sur un lien, appuyer sur un bouton, taper dans une zone de recherche et similaire...) sont acceptables et acceptés tant que le décalage se produit suite à une interaction et que l’effet est évident pour l'utilisateur.

Par exemple, si une interaction déclenche une requête réseau qui prend un certain temps, il est préférable de créer immédiatement de l'espace sur la page pour afficher un indicateur de chargement, ceci afin d’éviter un changement de disposition désagréable à la fin de la requête. Si l'utilisateur ne se rend pas compte que quelque chose est en train de se charger, ou ne sait pas quand la ressource sera prête, il peut essayer de cliquer sur autre chose en attendant - quelque chose qui pourrait s’insérer par en-dessous, créant alors une expérience non intuitive et frustrante.

Sachez que l'indicateur hadRecentInput sert pour les Layout Shifts qui se produisent dans les 500 millisecondes après une interaction, de sorte qu'ils sont exclus des calculs.

Animations et transitions

Les animations et les transitions, lorsqu'elles sont bien réalisées, sont un excellent moyen de mettre à jour le contenu de la page sans mauvaise surprise. Le contenu qui se déplace soudainement et de manière inattendue sur la page entraîne presque toujours une mauvaise expérience utilisateur. Mais un contenu qui se déplace progressivement et naturellement peut souvent aider à mieux comprendre ce qui se passe et à guider l’internaute entre les changements.

A cette fin, la propriété transform CSS permet d'animer des éléments sans déclencher de changement de disposition :

  • Au lieu de modifier les propriétés height et width, préférez transform: scale().
  • Pour déplacer des éléments, évitez de modifier les propriétés top, right, bottom, ou left, utilisez plutôt transform: translate().

Comment mesurer le Cumulative Layout Shift

Le Cumulative Layout Shift se mesure à l’aide des outils Lab ou Field de Google, et il est disponible dans les outils suivants : 

Les outils Field (Real User Monitoring)

Les outils Lab (Synthetic Monitoring)


Attention : les outils Lab (Synthetic Monitoring) chargent généralement des pages dans un environnement de synthèse, et ne permettent donc pas de mesurer les changements de mise en page qui se produisent en conditions réelles. Par conséquent, les valeurs CLS signalées par les outils Lab pour une page donnée peuvent être inférieures à ce qu’expérimentent des utilisateurs réels.

Mesurer le Cumulative Layout Shift en JavaScript 

La façon la plus simple de mesurer CLS (ainsi que toutes les métriques Field des Web Vitals) est avec la librairie web-vitals JavaScript, qui simplifie la mesure manuelle de CLS en une seule fonction :

import {getCLS} from 'web-vitals';
// Measure and log the current CLS value,
// any time it's ready to be reported.
getCLS(console.log);

Pour mesurer le CLS manuellement, vous pouvez utiliser l’API Layout Instability. L’exemple ci-dessous montre comment créer un PerformanceObserver pour relever les occurrences layout-shift et les loguer dans la console :

// Use a try/catch instead of feature detecting `layout-shift`
// support, since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
 const po = new PerformanceObserver((list) => {
   for (const entry of list.getEntries()) {
     console.log(entry);
   }
 });
 po.observe({type: 'layout-shift', buffered: true});
} catch (e) {
 // Do nothing if the browser doesn't support this API.
}

Le CLS est ainsi la somme de ces occurrences layout-shift individuelles qui ne se sont pas issues d’une action récente de l’utilisateur. Pour calculer CLS, il faut déclarer une variable qui stocke le score récent, puis l’incrémenter à chaque fois qu'un nouveau Layout Shift inattendu est détecté.

Plutôt que de signaler chaque modification de CLS (ce qui peut arriver très fréquemment), il est préférable de garder une trace de la valeur CLS récente et de la signaler à chaque fois que l'état du lifecycle state passe à hidden :

// Sends the passed data to an analytics endpoint. This code
// uses `/analytics`; you can replace it with your own URL.
function sendToAnalytics(data) {
 const body = JSON.stringify(data);
 // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
 (navigator.sendBeacon && navigator.sendBeacon('/analytics', body)) ||
     fetch('/analytics', {body, method: 'POST', keepalive: true});
}
// Use a try/catch instead of feature detecting `layout-shift`
// support, since some browsers throw when using the new `type` option.
// https://bugs.webkit.org/show_bug.cgi?id=209216
try {
 // Store the current layout shift score for the page.
 let cls = 0;
 function onLayoutShiftEntry(entry) {
   // Only count layout shifts without recent user input.
   if (!entry.hadRecentInput) {
     cls += entry.value;
   }
 }
 // Create a PerformanceObserver that calls `onLayoutShiftEntry` for each entry.
 const po = new PerformanceObserver((entryList) => {
   entryList.getEntries().forEach(onLayoutShiftEntry);
 });
 // Observe entries of type `layout-shift`, including buffered entries,
 // i.e. entries that occurred before calling `observe()` below.
 po.observe({
   type: 'layout-shift',
   buffered: true,
 });
 // Log the current CLS score any time the
 // page's lifecycle state changes to hidden.
 document.addEventListener('visibilitychange', () => {
   if (document.visibilityState === 'hidden') {
     // Force any pending records to be dispatched.
     po.takeRecords().forEach(onLayoutShiftEntry);
     // Report the CLS value to an analytics endpoint.
     sendToAnalytics({cls});
   }
 });
} catch (e) {
 // Do nothing if the browser doesn't support this API.
}

Comment améliorer le CLS 

Pour la plupart des sites web, vous pouvez éviter tous les changements inattendus qui dégradent l’UX (Layout Shifts) en respectant quelques principes essentiels :

  • Prévoyez toujours des attributs de taille sur vos images et éléments vidéo, ou réservez l'espace requis, par exemple avec CSS aspect ratio boxes. Cette technique garantit que le navigateur peut allouer la quantité d'espace suffisante pendant le chargement de l'image. Notez que vous pouvez également utiliser unsized-media feature policy pour forcer ce comportement dans les navigateurs qui les supportent.
  • N'insérez jamais de contenu au-dessus de contenu existant, sauf en réponse à une interaction de l'utilisateur. Cela garantit que tous les changements de disposition qui se produisent sont attendus.
  • Préférez les animations de transformation aux animations de propriétés qui déclenchent des changements de disposition des éléments sur une page. Animez les transitions de façon à fournir un contexte et une continuité d'un état à l'autre.

Enfin, pour aller plus loin sur les techniques d’amélioration du Cumulative Layout Shift, vous pouvez consulter le talk suivant d’Annie Sullivan à #PerfMatters (2020) : Understanding Cumulative Layout Shift.

Suivre les évolutions du Cumulative Layout Shift

Google corrige et fait évoluer les API utilisées pour mesurer les métriques, ainsi que la définition des métriques elles-mêmes. Ces modifications peuvent apparaître comme des améliorations ou des régressions dans vos rapports et tableaux de bord internes. Pour vous aider à suivre ces évolutions, les modifications sont consignées dans ce CHANGELOG (NdT : nous abordons régulièrement les évolutions des métriques webperf dans notre newsletter mensuelle, vous pouvez vous y abonner ici).

Vous souhaitez creuser le sujet en vidéo ? Le replay de notre webinaire dédié au CLS est ici :

Vous souhaitez approfondir vos connaissances sur
les métriques webperf ? Découvrez notre livre blanc :
"Décrypter et améliorer sa webperf"


Télécharger le livre blanc

 

L’article original en anglais est publié sur Web.dev


Hello SMX Paris !