.

Core Web Vitals Google : Cumulative Layout Shift (CLS)

Le Cumulative Layout Shift (CLS) est une métrique des Core Web Vitals prise en compte par Google Lighthouse de Pagespeed insight, qui est 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 viewportSon 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 FractionDistance 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.

Calcul du score CLS : une fenêtre de session maximale plafonnée à 5 secondes

NdT : en avril 2021, Google a fait évoluer le calcul du CLS. Il s'effectue sur une fenêtre de session maximale avec 1 seconde d'intervalle, plafonnée à 5 secondes.

Visualisation des changements de mise en page pour le calcul du Cumulative Layout Shift

Dans l'exemple ci-dessus, différents changements de mise en page se produisent au fil du temps lorsque l'utilisateur consulte la page. Chacun est représenté par une barre bleue. On voit ici que les barres bleues ont des hauteurs différentes, qui représentent le score de chaque changement de mise en page.
Une fenêtre de session commence avec le premier changement de disposition et continue de s'étendre jusqu'à ce qu'il y ait un espace sans changement de disposition. Lors du changement de disposition suivant, une nouvelle fenêtre de session démarre. Il y a 3 espaces sans changement de disposition, et donc 3 fenêtres de session dans cet exemple. Comme prévu dans la définition du CLS, les scores de chaque changement de mise en page sont additionnés, de sorte que le score de chaque fenêtre est la somme de ses changements de mise en page individuels.

Néanmoins... dans l'exemple ci-dessous, on observe un seul petit changement de disposition dans la 2ème fenêtre de session, avec un score très faible. Cela signifie que le score moyen est assez bas.
Mais que se passe-t-il si le développeur corrige ce petit changement de mise en page ? Le score est alors calculé uniquement sur la fenêtre de session 1, ce qui signifie que le score de la page double presque. Ce serait décourageant pour un développeur d'améliorer les changements de mise en page, si c'est pour constater que le score s'est détérioré. Et supprimer ce petit décalage de mise en page rendrait évidemment l'expérience utilisateur légèrement meilleurs, donc cela ne devrait pas dégrader le score, au contraire.

Core Web Vitals Google :: fenêtres de sessions pour le calcul du score Cumulative Layout Shift

Ainsi, pour pallier le problème posé par les moyennes de scores CLS générées à partir des changements de mise en page, Google a décidé de mesurer ces scores sur des fenêtres maximales plus petites et plafonnées. De ce fait, dans l'exemple ci-dessus, la fenêtre de session n°2 est alors ignorée, et seule la somme des changements de disposition dans la fenêtre de session 1 est signalée.

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 toprightbottom, 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 Core 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.
}

Pourquoi le Cumulative Layout Shift est différent entre les données Lab et Field sur PageSpeed Insights ?

PageSpeed Insights Google - CLS in Field vs. Lab data

Les effets des interactions de l'utilisateur sur CLS

Le score CLS mesuré avec des données Lab ne prend en compte que les changements de mise en page qui se produisent au-dessus de la ligne de flottaison et pendant le chargement, mais ce n'est qu'un sous-ensemble de ce que le CLS mesure réellement.

Sur le terrain, auprès d'utilisateurs réels, le CLS prend en compte tous les déplacements inattendus de la mise en page qui se produisent tout au long de la durée de vie de cette page, y compris les éléments qui se déplacent lorsque l'utilisateur fait défiler le contenu, ou en réponse à des requêtes réseau lentes après une interaction de l'utilisateur.

Par exemple, il est assez courant que des pages lazyloadent des images ou des iframes sans dimensions, ce qui peut entraîner des modifications de mise en page lorsque l'utilisateur fait défiler les sections de la page. Mais ces changements ne peuvent se produire que si l'utilisateur fait défiler la page vers le bas, ce qui n'est souvent pas détecté par des données Lab.

Le contenu personnalisé

Le contenu personnalisé - y compris les publicités ciblées et les tests A/B - affecte les éléments qui sont chargés sur une page. Il affecte également la manière dont ils sont chargés, car le contenu personnalisé est souvent chargé plus tard et inséré dans le contenu principal, ce qui entraîne des modifications de mise en page.

Pour remonter des données Lab, une page est généralement chargée soit sans contenu personnalisé, soit avec un contenu destiné à un "utilisateur test" générique, qui peut ou non déclencher les changements que les utilisateurs réels constatent.

Etant donné que les données de terrain incluent les expériences de tous les utilisateurs, la quantité (et le degré) de décalages de mise en page observés sur une page donnée dépendent fortement du contenu chargé.

Les effets de l'état de la mémoire cache et du bfcache sur le CLS

Deux des causes les plus courantes de décalage de la mise en page pendant le chargement sont les images et les iframes sans dimensions (comme mentionné ci-dessus), et les polices web qui se chargent lentement. Ces deux problèmes sont plus susceptibles d'affecter l'expérience lors de la première visite d'un site par un utilisateur, lorsque son cache est vide.

Si les ressources d'une page sont mises en cache, ou si la page elle-même est restaurée à partir du bfcache, le navigateur peut généralement afficher les images et les polices immédiatement, sans attendre leur téléchargement. Il peut en résulter des valeurs CLS plus faibles sur le terrain que celles rapportées par un outil de laboratoire.

Field ou Lab : quelles métriques prioriser pour optimiser le CLS ?

De manière générale, si vous disposez à la fois de données Field et de données Lab pour vos pages web, les données Field sont à privilégier pour prioriser vos efforts. Puisque les données Field représentent ce que vivent les utilisateurs réels, c'est le moyen le plus précis de comprendre réellement ce qui pose problème à vos utilisateurs et ce qui doit être optimisé.

Néanmoins, si vos données Field sont globalement bonnes, mais que vos données Lab montrent qu'il y a encore de la place pour des améliorations, c'est intéressant de creuser pour comprendre quelles optimisations supplémentaires peuvent être apportées.

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 :

  • Pour optimiser vos images, 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 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

A lire aussi :