Comment résoudre les problèmes de décalage de mise en page cumulé (CLS)

Publié: 2022-03-10
Résumé rapide ↬ L'initiative Core Web Vitals de Google a pris d'assaut les mondes du référencement et de la performance Web et de nombreux sites s'affairent à optimiser leur expérience de page pour maximiser le facteur de classement. La métrique Cumulative Layout Shift cause des problèmes à de nombreux sites, alors examinons les moyens de résoudre les problèmes liés à cette métrique.

Cumulative Layout Shift (CLS) tente de mesurer ces mouvements discordants de la page à mesure que le nouveau contenu - qu'il s'agisse d'images, de publicités ou autre - entre en jeu plus tard que le reste de la page. Il calcule un score basé sur la quantité de page qui se déplace de manière inattendue et à quelle fréquence. Ces décalages de contenu sont très gênants, vous faisant perdre votre place dans un article que vous avez commencé à lire ou, pire encore, vous faisant cliquer sur le mauvais bouton !

Dans cet article, je vais discuter de certains modèles frontaux pour réduire le CLS . Je ne vais pas trop parler de la mesure du CLS car j'en ai déjà parlé dans un article précédent. Je ne parlerai pas non plus trop des mécanismes de calcul du CLS : Google dispose d'une bonne documentation à ce sujet, et le guide presque complet de Jess Peck sur le changement de mise en page cumulatif est également une plongée approfondie dans ce domaine. Cependant, je vais donner un peu de contexte nécessaire pour comprendre certaines des techniques.

Pourquoi CLS est différent

CLS est, à mon avis, le plus intéressant des Core Web Vitals, en partie parce que c'est quelque chose que nous n'avons jamais vraiment mesuré ou optimisé auparavant. Ainsi, il faut souvent de nouvelles techniques et façons de penser pour tenter de l'optimiser. C'est une bête très différente des deux autres Core Web Vitals.

En regardant brièvement les deux autres Core Web Vitals, Largest Contentful Paint (LCP) fait exactement ce que son nom l'indique et est plus une variante des métriques de chargement précédentes qui mesurent la rapidité de chargement de la page. Oui, nous avons changé la façon dont nous avons défini l'expérience utilisateur du chargement de la page pour examiner la vitesse de chargement du contenu le plus pertinent , mais il s'agit essentiellement de réutiliser les anciennes techniques pour garantir que le contenu se charge le plus rapidement possible. Comment optimiser votre LCP devrait être un problème relativement bien compris pour la plupart des pages Web.

Le premier délai d'entrée (FID) mesure les retards dans les interactions et ne semble pas être un problème pour la plupart des sites. L'optimisation consiste généralement à nettoyer (ou à réduire !) Votre JavaScript et est généralement spécifique au site. Cela ne veut pas dire que résoudre les problèmes avec ces deux métriques est facile, mais ce sont des problèmes raisonnablement bien compris.

L'une des raisons pour lesquelles CLS est différent est qu'il est mesuré sur la durée de vie de la page - c'est la partie "cumulative" du nom ! Les deux autres Core Web Vitals s'arrêtent une fois que le composant principal est trouvé sur la page après le chargement (pour LCP), ou pour la première interaction (pour FID). Cela signifie que nos outils de laboratoire traditionnels, comme Lighthouse, ne reflètent souvent pas entièrement le CLS car ils ne calculent que le CLS de charge initial. Dans la vraie vie, un utilisateur fera défiler la page et peut obtenir plus de contenu en provoquant plus de changements.

CLS est également un peu un nombre artificiel qui est calculé en fonction de la quantité de page qui se déplace et de sa fréquence. Alors que LCP et FID sont mesurés en millisecondes, CLS est un nombre sans unité produit par un calcul complexe. Nous voulons que la page soit 0.1 ou moins pour passer ce Core Web Vital. Tout ce qui dépasse 0,25 est considéré comme "médiocre".

Les décalages causés par l'interaction de l'utilisateur ne sont pas comptés . Ceci est défini comme dans les 500 ms d'un ensemble spécifique d'interactions utilisateur bien que les événements de pointeur et le défilement soient exclus. Il est présumé qu'un utilisateur cliquant sur un bouton peut s'attendre à ce que du contenu apparaisse, par exemple en développant une section réduite.

CLS consiste à mesurer les changements inattendus . Le défilement ne devrait pas entraîner le déplacement du contenu si une page est construite de manière optimale, et de la même manière, le survol d'une image de produit pour obtenir une version agrandie, par exemple, ne devrait pas non plus faire sauter l'autre contenu. Mais il y a bien sûr des exceptions et ces sites doivent réfléchir à la manière de réagir à cela.

CLS évolue également en permanence avec des ajustements et des corrections de bogues. Un changement plus important vient d'être annoncé qui devrait donner un peu de répit aux pages de longue durée, comme les applications à page unique (SPA) et les pages à défilement infini, qui, selon beaucoup, étaient injustement pénalisées dans CLS. Plutôt que d'accumuler des décalages sur toute la durée de la page pour calculer le score CLS comme cela a été fait jusqu'à présent, le score sera calculé sur la base du plus grand ensemble de décalages dans une fenêtre temporelle spécifique.

Cela signifie que si vous avez trois blocs de CLS de 0,05, 0,06 et 0,04, cela aurait été précédemment enregistré comme 0,15 (c'est-à-dire au-dessus de la "bonne" limite de 0,1), alors qu'il sera maintenant noté comme 0,06. Il est toujours cumulatif dans le sens où le score peut être composé de changements distincts au cours de cette période (c'est-à-dire si ce score CLS de 0,06 a été causé par trois changements distincts de 0,02), mais il n'est tout simplement plus cumulatif sur la durée de vie totale de la page. .

Cela dit, si vous résolvez les causes de ce changement de 0,06, votre CLS sera alors signalé comme le plus grand suivant (0,05), de sorte qu'il examine toujours tous les changements au cours de la durée de vie de la page - c'est juste choisir de signaler uniquement le plus grand comme le score CLS.

Après cette brève introduction à une partie de la méthodologie sur CLS, passons à certaines des solutions ! Toutes ces techniques impliquent essentiellement de réserver la bonne quantité d'espace avant le chargement de contenu supplémentaire - qu'il s'agisse de contenu multimédia ou de contenu injecté par JavaScript, mais il existe différentes options disponibles pour les développeurs Web pour ce faire.

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

Définir la largeur et la hauteur des images et des iFrames

J'ai déjà écrit à ce sujet, mais l'une des choses les plus simples que vous puissiez faire pour réduire le CLS est de vous assurer que les attributs width et height sont définis sur vos images . Sans eux, une image entraînera le déplacement du contenu suivant pour lui faire place après son téléchargement :

Un exemple de mise en page avec un titre et deux paragraphes, où le deuxième paragraphe doit se déplacer vers le bas pour faire de la place pour une image.
Changement de mise en page après le chargement de l'image. ( Grand aperçu )

Il s'agit simplement de changer le balisage de votre image à partir de :

 <img src="hero_image.jpg" alt="...">

Pour:

 <img src="hero_image.jpg" alt="..." width="400" height="400">

Vous pouvez trouver les dimensions de l'image en ouvrant DevTools et en survolant (ou en tapotant) l'élément.

Capture d'écran des outils de développement Chrome montrant l'image, la taille du rendu, le rapport hauteur/largeur rendu, la taille intrinsèque, le rapport hauteur/largeur intrinsèque, la taille du fichier et la source actuelle.
Chrome DevTools affiche les dimensions et les proportions de l'image lorsque vous survolez un élément. ( Grand aperçu )

Je conseille d'utiliser la taille intrinsèque (qui est la taille réelle de la source de l'image) et le navigateur les réduira ensuite à la taille rendue lorsque vous utiliserez CSS pour les modifier.

Astuce : Si, comme moi, vous ne vous souvenez pas s'il s'agit de la largeur et de la hauteur ou de la hauteur et de la largeur, considérez-les comme des coordonnées X et Y, donc, comme X, la largeur est toujours donnée en premier.

Si vous avez des images réactives et que vous utilisez CSS pour modifier les dimensions de l'image (par exemple, pour la contraindre à une max-width de 100 % de la taille de l'écran), ces attributs peuvent être utilisés pour calculer la height - à condition que vous vous souveniez de remplacer ceci par auto dans votre CSS :

 img { max-width: 100%; height: auto; }

Tous les navigateurs modernes le supportent maintenant, mais pas jusqu'à récemment, comme indiqué dans mon article. Cela fonctionne également pour les éléments <picture> et les images srcset (définissez la width et la height sur l'élément img de secours), mais pas encore pour les images de différents rapports d'aspect - cela est en cours d'élaboration, et jusque-là, vous devez toujours définir la width et la height car toutes les valeurs seront meilleures que les valeurs par défaut 0 par 0 !

Cela fonctionne également sur les images natives chargées paresseuses (bien que Safari ne prenne pas encore en charge le chargement paresseux natif par défaut).

La nouvelle propriété CSS aspect-ratio

La technique de width et de height ci-dessus, pour calculer la hauteur des images réactives, peut être généralisée à d'autres éléments à l'aide de la nouvelle propriété CSS aspect-ratio , désormais prise en charge par les navigateurs basés sur Chromium et Firefox, mais également dans Safari Technology Preview. j'espère que cela signifie qu'il arrivera bientôt dans la version stable.

Vous pourrez donc l'utiliser sur une vidéo embarquée par exemple au format 16:9 :

 video { max-width: 100%; height: auto; aspect-ratio: 16 / 9; }
 <video controls width="1600" height="900" poster="..."> <source src="/media/video.webm" type="video/webm"> <source src="/media/video.mp4" type="video/mp4"> Sorry, your browser doesn't support embedded videos. </video>

Fait intéressant, sans définir la propriété aspect-ratio , les navigateurs ignoreront la hauteur des éléments vidéo réactifs et utiliseront un rapport d'aspect par défaut de 2: 1, donc ce qui précède est nécessaire pour éviter un changement de disposition ici.

À l'avenir, il devrait même être possible de définir dynamiquement le aspect-ratio fonction des attributs de l'élément en utilisant aspect-ratio: attr(width) / attr(height); mais malheureusement ce n'est pas encore supporté.

Ou vous pouvez même utiliser le aspect-ratio sur un élément <div> pour une sorte de contrôle personnalisé que vous créez pour le rendre réactif :

 #my-square-custom-control { max-width: 100%; height: auto; width: 500px; aspect-ratio: 1; }
 <div></div>

Pour les navigateurs qui ne prennent pas en charge le aspect-ratio vous pouvez utiliser l'ancien hack padding-bottom mais, avec la simplicité du nouveau aspect-ratio et une large prise en charge (surtout une fois que cela passe de Safari Technical Preview à Safari normal), il est difficile de justifier cette ancienne méthode.

Chrome est le seul navigateur qui renvoie CLS à Google et il prend en charge la signification aspect-ratio qui résoudra vos problèmes CLS en termes de Core Web Vitals. Je n'aime pas donner la priorité aux métriques par rapport aux utilisateurs, mais le fait que les autres navigateurs Chromium et Firefox l'aient et que Safari, espérons-le, bientôt, et qu'il s'agisse d'une amélioration progressive signifie que je dirais que nous sommes au point où nous peut laisser le piratage du fond de remplissage derrière et écrire un code plus propre.

Faites un usage libéral de min-height

Pour les éléments qui n'ont pas besoin d'une taille réactive mais d'une hauteur fixe, envisagez d'utiliser min-height . Cela pourrait être pour un en-tête à hauteur fixe , par exemple, et nous pouvons avoir différents en-têtes pour les différents points d'arrêt en utilisant les requêtes multimédias comme d'habitude :

 header { min-height: 50px; } @media (min-width: 600px) { header { min-height: 200px; } }
 <header> ... </header>

Bien sûr, il en va de même pour min-width minimale des éléments placés horizontalement, mais c'est normalement la hauteur qui cause les problèmes de CLS.

Une technique plus avancée pour le contenu injecté et les sélecteurs CSS avancés consiste à cibler lorsque le contenu attendu n'a pas encore été inséré. Par exemple, si vous aviez le contenu suivant :

 <div class="container"> <div class="main-content">...</div> </div>

Et un div supplémentaire est inséré via JavaScript :

 <div class="container"> <div class="additional-content">.../div> <div class="main-content">...</div> </div>

Ensuite, vous pouvez utiliser l'extrait de code suivant pour laisser de l'espace pour du contenu supplémentaire lors du rendu initial de la div main-content .

 .main-content:first-child { margin-top: 20px; }

Ce code créera en fait un décalage vers l'élément de main-content car la marge compte comme faisant partie de cet élément, de sorte qu'il semblera se déplacer lorsqu'il sera supprimé (même s'il ne se déplace pas réellement à l'écran). Cependant, au moins le contenu en dessous ne sera pas déplacé et devrait donc réduire le CLS.

Alternativement, vous pouvez utiliser le pseudo-élément ::before pour ajouter l'espace afin d' éviter également le décalage sur l'élément de main-content :

 .main-content:first-child::before { content: ''; min-height: 20px; display: block; }

Mais en toute honnêteté, la meilleure solution est d'avoir la div dans le HTML et d'utiliser min-height à ce sujet.

Vérifier les éléments de secours

J'aime utiliser l'amélioration progressive pour fournir un site Web de base, même sans JavaScript dans la mesure du possible. Malheureusement, cela m'a surpris récemment sur un site que je maintiens lorsque la version de secours non-JavaScript était différente de celle lorsque le JavaScript a démarré.

Le problème était dû au bouton de menu "Table des matières" dans l'en-tête. Avant que JavaScript ne démarre, il s'agit d'un lien simple, conçu pour ressembler au bouton qui vous amène à la page Table des matières. Une fois que JavaScript démarre, il devient un menu dynamique pour vous permettre de naviguer directement vers la page à laquelle vous souhaitez accéder à partir de cette page.

Captures d'écran de deux composants de navigation de la table des matières ressemblant à un bouton. Avec JavaScript, cela ouvre un menu dynamique comme indiqué dans la deuxième image.
Un composant d'en-tête de table des matières qui est initialement rendu sous la forme d'un simple lien (en haut), puis amélioré avec JavaScript pour devenir un menu dynamique (en bas). ( Grand aperçu )

J'ai utilisé des éléments sémantiques et donc utilisé un élément d'ancrage ( <a href="#table-of-contents"> ) pour le lien de secours, mais je l'ai remplacé par un <button> pour le menu dynamique piloté par JavaScript. Ceux-ci avaient le même style, mais le lien de secours était de quelques pixels plus petit que le bouton !

C'était si petit, et le JavaScript s'activait généralement si rapidement, que je n'avais pas remarqué qu'il était désactivé. Cependant, Chrome l'a remarqué lors du calcul du CLS et, comme cela se trouvait dans l'en-tête, il a déplacé la page entière de quelques pixels vers le bas . Cela a donc eu un impact considérable sur le score CLS - suffisamment pour faire tomber toutes nos pages dans la catégorie "Besoin d'amélioration".

C'était une erreur de ma part, et le correctif consistait simplement à synchroniser les deux éléments (cela aurait également pu être résolu en définissant une min-height sur l'en-tête, comme indiqué ci-dessus), mais cela m'a un peu dérouté. Je suis sûr que je ne suis pas le seul à avoir fait cette erreur, alors soyez conscient de la façon dont la page s'affiche sans JavaScript. Vous ne pensez pas que vos utilisateurs désactivent JavaScript ? Tous vos utilisateurs ne sont pas JS lorsqu'ils téléchargent votre JS.

Les polices Web provoquent des changements de mise en page

Les polices Web sont une autre cause fréquente de CLS car le navigateur calcule initialement l'espace nécessaire en fonction de la police de secours, puis le recalcule lorsque la police Web est téléchargée. Habituellement, le CLS est petit, à condition qu'une police de secours de taille similaire soit utilisée, si souvent ils ne causent pas suffisamment de problèmes pour faire échouer Core Web Vitals, mais ils peuvent néanmoins être choquants pour les utilisateurs.

Deux captures d'écran d'un article de Smashing Magazine avec des polices différentes. Le texte est sensiblement de taille différente et une phrase supplémentaire peut s'intégrer lorsque les polices Web sont utilisées.
Article de Smashing Magazine avec police de secours et polices Web complètes. ( Grand aperçu )

Malheureusement, même le préchargement des polices Web n'aidera pas ici car, bien que cela réduise le temps pendant lequel les polices de secours sont utilisées (ce qui est bon pour les performances de chargement - LCP), il faut encore du temps pour les récupérer , et donc les secours seront toujours utilisés par le navigateur dans la plupart des cas, donc n'évite pas CLS. Cela dit, si vous savez qu'une police Web est nécessaire sur la page suivante (disons que vous êtes sur une page de connexion et que vous savez que la page suivante utilise une police spéciale), vous pouvez les pré-extraire.

Pour éviter complètement les changements de mise en page induits par les polices , nous pourrions bien sûr ne pas utiliser de polices Web du tout - y compris en utilisant des polices système à la place, ou en utilisant font-display: optional pour ne pas les utiliser si elles ne sont pas téléchargées à temps pour le rendu initial. Mais aucun de ceux-ci n'est très satisfaisant, pour être honnête.

Une autre option consiste à s'assurer que les sections sont de taille appropriée (par exemple avec min-height ) de sorte que même si le texte qu'elles contiennent peut se déplacer un peu, le contenu en dessous ne sera pas abaissé même lorsque cela se produit. Par exemple, la définition d'une min-height minimale sur l'élément <h1> pourrait empêcher tout l'article de se déplacer vers le bas si des polices légèrement plus hautes sont chargées - à condition que les différentes polices ne provoquent pas un nombre de lignes différent. Cela réduira l'impact des décalages, cependant, pour de nombreux cas d'utilisation (par exemple, les paragraphes génériques), il sera difficile de généraliser une hauteur minimale.

Ce qui me passionne le plus pour résoudre ce problème, ce sont les nouveaux descripteurs de polices CSS qui vous permettent d'ajuster plus facilement les polices de secours dans CSS :

 @font-face { font-family: 'Lato'; src: url('/static/fonts/Lato.woff2') format('woff2'); font-weight: 400; } @font-face { font-family: "Lato-fallback"; size-adjust: 97.38%; ascent-override: 99%; src: local("Arial"); } h1 { font-family: Lato, Lato-fallback, sans-serif; }

Auparavant, l'ajustement de la police de secours nécessaire à l'aide de l'API Font Loading en JavaScript était plus compliqué, mais cette option qui devrait sortir très bientôt pourrait enfin nous donner une solution plus simple et plus susceptible de gagner du terrain. Voir mon article précédent sur ce sujet pour plus de détails sur cette innovation à venir et plus de ressources à ce sujet.

Modèles initiaux pour les pages rendues côté client

De nombreuses pages rendues côté client, ou applications à page unique, rendent une page de base initiale en utilisant uniquement HTML et CSS, puis "hydratent" le modèle après le téléchargement et l'exécution de JavaScript.

Il est facile pour ces modèles initiaux de se désynchroniser avec la version JavaScript car de nouveaux composants et fonctionnalités sont ajoutés à l'application dans JavaScript mais pas ajoutés au modèle HTML initial qui est rendu en premier. Cela provoque alors CLS lorsque ces composants sont injectés par JavaScript.

Passez donc en revue tous vos modèles initiaux pour vous assurer qu'ils sont toujours de bons espaces réservés initiaux. Et si le modèle initial se compose de <div> vides, utilisez les techniques ci-dessus pour vous assurer qu'ils sont dimensionnés de manière appropriée pour essayer d'éviter tout décalage.

De plus, la div initiale qui est injectée avec l'application doit avoir une min-height pour éviter qu'elle ne soit initialement rendue avec une hauteur de 0 avant même que le modèle initial ne soit inséré.

 <div></div>

Tant que la min-height est supérieure à la plupart des fenêtres , cela devrait éviter tout CLS pour le pied de page du site Web, par exemple. Le CLS n'est mesuré que lorsqu'il se trouve dans la fenêtre d'affichage et a donc un impact sur l'utilisateur. Par défaut, un div vide a une hauteur de 0px, alors donnez-lui une min-height minimale qui est plus proche de ce que sera la hauteur réelle lors du chargement de l'application.

Assurez-vous que les interactions utilisateur se terminent dans les 500 ms

Les interactions de l'utilisateur qui entraînent un changement de contenu sont exclues des scores CLS. Celles-ci sont limitées à 500 ms après l'interaction. Donc, si vous cliquez sur un bouton et effectuez un traitement complexe qui prend plus de 500 ms, puis affichez un nouveau contenu, votre score CLS va en souffrir.

Vous pouvez voir si le changement a été exclu dans Chrome DevTools en utilisant l' onglet Performances pour enregistrer la page, puis en trouvant les changements comme indiqué dans la capture d'écran suivante. Ouvrez DevTools, accédez à l'onglet Performances très intimidant (mais très utile une fois que vous avez compris !), puis cliquez sur le bouton d'enregistrement en haut à gauche (encerclé sur l'image ci-dessous) et interagissez avec votre page, et arrêtez l'enregistrement une fois Achevée.

Capture d'écran de Chrome Dev Tools avec une équipe sélectionnée et le résumé de celle-ci montre qu'elle a reçu une entrée récente et que l'équipe n'est donc pas incluse dans le score cumulé.
Utilisation de l'onglet Performances dans Chrome Dev Tools pour voir si les quarts de travail sont exclus en raison d'une entrée récente. ( Grand aperçu )

Vous verrez une pellicule de la page dans laquelle j'ai chargé certains des commentaires d'un autre article de Smashing Magazine. Ainsi, dans la partie que j'ai encerclée, vous pouvez à peu près distinguer le chargement des commentaires et le bas de page rouge décalé hors écran. Plus bas dans l'onglet Performances , sous la ligne Expérience , Chrome mettra une boîte rouge-rosâtre pour chaque quart de travail et lorsque vous cliquerez dessus, vous obtiendrez plus de détails dans l'onglet Résumé ci-dessous.

Ici, vous pouvez voir que nous avons obtenu un score massif de 0,3359 - bien au-delà du seuil de 0,1 que nous visons, mais le score cumulatif n'a pas inclus cela, car Had recent input est défini sur Uses.

S'assurer que les interactions ne modifient que le contenu dans les 500 ms limite ce que First Input Delay tente de mesurer, mais il y a des cas où l'utilisateur peut voir que l'entrée a eu un effet (par exemple, un spinner de chargement est affiché) donc le FID est bon, mais le contenu peut ne pas être ajouté à la page avant la limite de 500 ms, donc CLS est mauvais.

Idéalement, toute l'interaction sera terminée en 500 ms, mais vous pouvez faire certaines choses pour réserver l'espace nécessaire en utilisant les techniques ci-dessus pendant que le traitement est en cours, de sorte que si cela prend plus que les 500 ms magiques, alors vous avez déjà effectué le quart de travail et ne sera donc pas pénalisé pour cela. Ceci est particulièrement utile lors de la récupération de contenu du réseau qui pourrait être variable et hors de votre contrôle.

Les autres éléments à surveiller sont les animations qui prennent plus de 500 ms et peuvent donc avoir un impact sur CLS. Bien que cela puisse sembler un peu restrictif, le but de CLS n'est pas de limiter le "fun", mais de définir des attentes raisonnables d'expérience utilisateur et je ne pense pas qu'il soit irréaliste de s'attendre à ce que cela prenne 500 ms ou moins. Mais si vous n'êtes pas d'accord ou si vous avez un cas d'utilisation qu'ils n'ont peut-être pas envisagé, l'équipe Chrome est ouverte aux commentaires à ce sujet.

JavaScript synchrone

La dernière technique dont je vais parler est un peu controversée car elle va à l'encontre des conseils bien connus en matière de performances Web, mais elle peut être la seule méthode dans certaines situations. Fondamentalement, si vous avez du contenu dont vous savez qu'il va provoquer des décalages, une solution pour éviter les décalages est de ne pas le rendre tant qu'il n'est pas stabilisé !

Le code HTML ci-dessous masquera initialement la div , puis chargera du code JavaScript bloquant le rendu pour remplir la div , puis l'affichera. Comme le JavaScript bloque le rendu, rien en dessous ne sera rendu (y compris le deuxième bloc de style pour l'afficher) et donc aucun changement ne sera encouru.

 <style> .cls-inducing-div { display: none; } </style> <div class="cls-inducing-div"></div> <script> ... </script> <style> .cls-inducing-div { display: block; } </style>

Il est important d' intégrer le CSS dans le HTML avec cette technique, afin qu'elle soit appliquée dans l'ordre. L'alternative consiste à afficher le contenu avec JavaScript lui-même, mais ce que j'aime dans la technique ci-dessus, c'est qu'elle affiche toujours le contenu même si JavaScript échoue ou est désactivé par le navigateur.

Cette technique peut également être appliquée avec du JavaScript externe, mais cela entraînera plus de retard qu'un script en ligne car le JavaScript externe est demandé et téléchargé. Ce délai peut être minimisé en préchargeant la ressource JavaScript afin qu'elle soit disponible plus rapidement une fois que l'analyseur atteint cette section de code :

 <head> ... <link rel="preload" href="cls-inducing-javascript.js" as="script"> ... </head> <body> ... <style> .cls-inducing-div { display: none; } </style> <div class="cls-inducing-div"></div> <script src="cls-inducing-javascript.js"></script> <style> .cls-inducing-div { display: block; } </style> ... </body>

Maintenant, comme je l'ai dit, je suis sûr que cela fera grincer des dents certains spécialistes des performances Web, car le conseil est d'utiliser async, defer ou le nouveau type="module" (qui sont defer -ed par défaut) sur JavaScript spécifiquement pour éviter de bloquer render , alors que nous faisons l'inverse ici ! Cependant, si le contenu ne peut pas être prédéterminé et qu'il va provoquer des changements discordants, alors il n'y a pas grand intérêt à le rendre tôt.

J'ai utilisé cette technique pour une bannière cookie qui se chargeait en haut de la page et déplaçait le contenu vers le bas :

Une capture d'écran d'une page Web, où le contenu est décalé vers le bas lorsqu'une bannière de cookie est ajoutée en haut de la page.
Un avis de cookie en haut de la page ou une autre bannière peut déplacer le contenu vers le bas. ( Grand aperçu )

Cela nécessitait de lire un cookie pour voir s'il fallait ou non afficher la bannière de cookie et, bien que cela puisse être effectué côté serveur, il s'agissait d'un site statique sans possibilité de modifier dynamiquement le code HTML renvoyé.

Les bannières de cookies peuvent être implémentées de différentes manières pour éviter le CLS. Par exemple, en les plaçant en bas de la page ou en les superposant au-dessus du contenu, plutôt que de déplacer le contenu vers le bas. Nous avons préféré garder le contenu en haut de la page, nous avons donc dû utiliser cette technique pour éviter les décalages. Il existe diverses autres alertes et bannières que les propriétaires de sites peuvent préférer voir en haut de la page pour diverses raisons.

J'ai également utilisé cette technique sur une autre page où JavaScript déplace le contenu dans les colonnes "principale" et "à côté" (pour des raisons que je n'aborderai pas, il n'était pas possible de le construire correctement en HTML côté serveur). Encore une fois, en masquant le contenu, jusqu'à ce que JavaScript ait réorganisé le contenu, et seulement ensuite en l'affichant, on a évité les problèmes CLS qui faisaient baisser le score CLS de ces pages. Et encore une fois, le contenu est automatiquement affiché même si le JavaScript ne s'exécute pas pour une raison quelconque et que le contenu non décalé est affiché.

L'utilisation de cette technique peut avoir un impact sur d'autres métriques (en particulier LCP et aussi First Contentful Paint) car vous retardez le rendu, et bloquez également potentiellement le préchargement des navigateurs, mais c'est un autre outil à considérer dans les cas où aucune autre option n'existe.

Conclusion

Le changement de mise en page cumulé est causé par la modification des dimensions du contenu ou par l'injection tardive de nouveau contenu dans la page par l'exécution tardive de JavaScript. Dans cet article, nous avons discuté de divers trucs et astuces pour éviter cela. Je suis heureux que les Core Web Vitals aient braqué les projecteurs sur ce problème irritant - pendant trop longtemps, nous les développeurs Web (et je m'inclus définitivement dans cela) avons ignoré ce problème.

Le nettoyage de mes propres sites Web a conduit à une meilleure expérience pour tous les visiteurs. Je vous encourage également à examiner vos problèmes CLS , et j'espère que certains de ces conseils vous seront utiles lorsque vous le ferez. Qui sait, vous arriverez peut-être même à atteindre le score insaisissable de 0 CLS pour toutes vos pages !

Davantage de ressources

  • Articles Core Web Vitals ici sur Smashing Magazine, y compris le mien sur le réglage de la largeur et de la hauteur des images, la mesure des Core Web Vitals et les descripteurs de polices CSS.
  • Documentation Core Web Vitals de Google, y compris leur page sur CLS.
  • Plus de détails sur le changement récent apporté à CLS, puis ce changement a commencé à être mis à jour dans divers outils de Google.
  • Le CLS Changelog détaillant les changements dans chaque version de Chrome.
  • Le guide presque complet du changement de mise en page cumulatif par Jess Peck.
  • Changement de mise en page cumulatif : mesurez et évitez l'instabilité visuelle par Karolina Szczur.
  • Un générateur GIF Layout Shift pour aider à générer des démonstrations partageables de CLS.