Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Tu fais du Web et tu connais pas les Layout Shi...

Tu fais du Web et tu connais pas les Layout Shifts ?! Nan mais...

Les "Cumulative Layout Shifts" seraient-ils un problème majeur selon Google et pourtant... méconnu de la plupart des intégrateurs et intégratrices ?

La préoccupation consistant à "Réduire les Layout Shifts" couvre une large palette de domaines du Web dont l'UX, HTML, CSS, la Performance, voire le Référencement.

Voyons donc comment s'y prendre pour atténuer ces comportements néfastes (surtout du côté CSS parce que c'est le plus impactant et que c'est ce que je connais le mieux !).

Raphael Goetter

October 05, 2022
Tweet

More Decks by Raphael Goetter

Other Decks in Design

Transcript

  1. Depuis 2003 Un forum, des tutos, un service d'emploi Opensource

    et gratuit 30000 visiteurs / jour 50000 membres sur le forum .com Communauté d'apprentissage
  2. .fr Depuis 2006 On fait des sites web performants et

    accessibles On dispense des formations On est une petite équipe d'une 10aine de personnes On a un peu l’accent alsacien Agence web, organisme de formation
  3. big Merci ! Merci à Eroan pour son partage de

    connaissances et conseils avisés sur ce sujet https://agencewebperformance.fr/
  4. Layout Shifts “ Instabilités graphiques au chargement de la page

    qui dégradent l'expérience utilisateur. OK, alors c'est quoi des ?
  5. https://web.dev/cls/ Mouais c'est pas clair tout ça, tu me montres

    ? spoiler alert : le design de la page va changer au moment de l'interaction avec le visiteur
  6. Le Cumulative Layout Shift fait partie des Core Web Vitals.

    Google a annoncé utiliser les Core Web Vitals comme signal de ranking dès 2021. 🤯 Pourquoi c'est important ?
  7. “ Ce sujet à lui seul couvre les thèmes :

    UX, HTML, CSS, Performance... et SEO Cumulative Layout Shifts
  8. Outils en ligne (de notre ami Google) https://pagespeed.web.dev/ (le plus

    complet à ce jour) https://www.webpagetest.org/
  9. Outils en local (opensource, multibrowsers) Lighthouse (toi-même tu connais) Chrome

    DevTools (extension Firefox et Edge) SpeedVitals (extension Chrome) Web Vitals
  10. Bon, du coup, comment on évite ces Layout Shifts ?

    Réserver l'espace pour les publicités ou les iframes Diminuer le nombre de contenus injectés dynamiquement Construire des pages en préférant des zones de tailles fixes, non déterminées par leur contenu Indiquer largeur et hauteur des images et vidéos Précharger les polices pour éviter les comportements FOIT ou FOUT Concevoir des animations performantes
  11. .container { display: grid; grid-template-columns: 1fr 1fr 1fr; } 1

    2 3 4 méthode 1 .container { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; } 1 2 3 4 5 méthode 2
  12. méthode 2 grid-auto-flow .container { display: grid; grid-auto-flow: column; grid-auto-columns:

    1fr; } 1 2 3 4 5 je suis le temps qui passe... layout shift layout shift layout shift layout shift
  13. "auto" min-content max-content fit-content 1fr flex-shrink flex-grow stretch min-width: auto

    width: auto valeur connue par le navigateur que lorsque tous les contenus (texte, polices, images, médias) sont chargés et dimensionnés
  14. Flexbox Grid Layout Conçu pour s'adapter aux contenus. = Plus

    sensible aux Layout Shifts Flexbox est designé pour être fluide par défaut. Conçu pour englober les contenus. = Moins sensible aux Layout Shifts 💪 Grid Layout est designé pour être rigide par défaut. <table>, float, inline-block, ... 💩
  15. .container { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; } 1

    2 3 4 5 .container { display: grid; grid-template-columns: 1fr 1fr 1fr; } 1 2 3 4 1 2 on vient d'en parler il y a 5min, faut suivre un peu...
  16. .flex-item { flex-grow: 1; } 1 2 3 .flex-item {

    flex: 1; } 1 2 3 1 2 = flex-grow: 1 & flex-basis: 0 = flex-grow: 1 & flex-basis: auto
  17. .flex-item { flex: 1; } 1 2 3 .flex-item {

    flex: 1 0 0; } 1 2 3 1 2 = flex-grow: 1 & flex-shrink: 1
  18. .flex-item { flex: 1; } 1 2 3 .flex-item {

    flex: 1; min-width: 0; } 1 2 3 4 1 2 par défaut min-width vaut "auto" sur un flex item
  19. .container { display: grid; grid-template-columns: 1fr 1fr; } 1 2

    3 4 .container { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); } 1 2 3 4 1 2 taille mini = min-content
  20. .container { display: grid; grid-template-columns: repeat(auto-fill, 100px); } 1 2

    3 4 .container { display: grid; grid-template-columns: repeat(auto-fit, 100px); } 1 2 3 4 1 2 auto-fit supprime les colonnes inutiles quand elles sont vides de contenu
  21. Utilisez Grid Layout en priorité tant que possible, et Flexbox

    si nécessaire. Tentez de limiter les valeurs automatiques, dépendantes du contenu. Si vous utilisez un framework, jetez un oeil sous le capot Conclusion Layout Shifts dûs à la mise en page par ex. dans Bootstrap un élément en .col-6 vaudra flex: 0 0 auto; width: 50%;
  22. Charger CSS de manière asynchrone (via JS) La propriété order

    Les propriétés row-reverse / column-reverse Les propriétés flex, flex-grow, flex-shrink (déjà vu) La valeur space-between (et semblables) si le nombre d'éléments est variable Bonus track CSS les trucs CSS qui génèrent des Layout Shifts source : https://www.codecada.com/serp/16/how-css-flexbox-model-can-cause-cummulative-layout-shifts
  23. img { margin-left: 0; transition: 0.5s; } img:hover { margin-left:

    100px; } ooh la jolie transition ! @keyframes pika { to { position: absolute; left: 100px; } } img:hover { animation: pika 0.5s; } ooh la belle animation ! 👎
  24. animation et perfs L'étape "Render tree" fait le tri entre

    les informations de contenu (HTML), de styles (CSS) et de scripts (JS). Il écarte les éléments invisibles (meta, scripts, mais aussi display: none, etc.) et ne conserve que ce qui sera affiché. L'étape "Layout" (ou Reflow) calcule la taille exacte et la position de chaque élément du Render tree. L'étape "Paint" (ou Repaint) dessine pixel par pixel chaque couleur sur la page. L'étape "Compositing" sépare la page en plusieurs calques indépendants afin d'être traités de manière autonome.
  25. CPU GPU Render tree + Layout display margin padding width,

    height position top, right, bottom, left border-width Paint color background-color background-image box-shadow, text-shadow clip-path border-color filter Composite transform translate, rotate, scale opacity will-change
  26. img { margin-left: 0; transition: 0.5s; } img:hover { margin-left:

    100px; } Transition avec Layout + Paint Transition Composite img { translate: 0; transition: translate 0.5s; } img:hover { translate: 100px; } 👎 👍 img { margin-left: 0; transition: 0.5s; will-change: margin-left; } img:hover { margin-left: 100px; } ou bien :
  27. Solution 1 : Animer de préférence les propriétés dites "composites"

    (transform, translate, opacity) Solution 2 : si la solution 1 n'est pas envisageable, appliquer la propriété will-change Conclusion Layout Shift dûs aux transitions et animations
  28. <img src="(chemin)" alt=""> <p>Lorem Elsass...</p> 1 2 Lorem Elsass Ipsum

    mitt picon bière munster du ftomi! Ponchour bisame. Bibbeleskaas jetz rossbolla sech choucroute un schwanz geburtstàg, Chinette dû, ìch bier deppfele schiesser. Flammekueche de knèkes Seppele gal! a hopla geburtstàg, alles fraü Chulia Roberts oder knäckes dûû blottkopf. Noch bredele schissabibala, yeuh e schmutz. largeur du parent : 200px 1 on dirait bien que l'image n'est pas encore chargée... suspense... il semble que je souhaite afficher une image...
  29. <img src="(chemin)" alt=""> 1 Lorem Elsass Ipsum mitt picon bière

    munster du ftomi! Ponchour bisame. Bibbeleskaas jetz rossbolla sech choucroute un schwanz geburtstàg, Chinette dû, ìch bier deppfele schiesser. Flammekueche de knèkes Seppele gal! a hopla geburtstàg, alles fraü Chulia Roberts oder knäckes dûû blottkopf. Noch bredele schissabibala, yeuh e schmutz. image 200 x 100px largeur du parent : 200px l'image est chargée, elle crée un Layout Shift (pas bien !) 1
  30. <img src="(chemin)" alt="" width="200" height="100"> 1 Lorem Elsass Ipsum mitt

    picon bière munster du ftomi! Ponchour bisame. Bibbeleskaas jetz rossbolla sech choucroute un schwanz geburtstàg, Chinette dû, ìch bier deppfele schiesser. Flammekueche de knèkes Seppele gal! a hopla geburtstàg, alles fraü Chulia Roberts oder knäckes dûû blottkopf. Noch bredele schissabibala, yeuh e schmutz. largeur du parent : 200px l'espace est réservé avant même que l'image ne soit chargée 2
  31. <img src="(chemin)" alt="" width="200" height="100"> 1 Lorem Elsass Ipsum mitt

    picon bière munster du ftomi! Ponchour bisame. Bibbeleskaas jetz rossbolla sech choucroute un schwanz geburtstàg, Chinette dû, ìch bier deppfele schiesser. Flammekueche de knèkes Seppele gal! a hopla geburtstàg, alles fraü Chulia Roberts oder knäckes dûû blottkopf. Noch bredele schissabibala, yeuh e schmutz. image 200 x 100px largeur du parent : 200px et hop, pas de Layout Shift ! 2 bah c'est bien beau mais moi je fais du Responsive et ma taille d'image au départ est variable, mettons 2000x1000 tiens !
  32. <img src="(chemin)" alt="" width="2000" height="1000"> 1 image 2000 x 1000px

    largeur du parent : 200px bah forcément ça déborde ! 3
  33. <img src="(chemin)" alt="" width="2000" height="1000"> 1 largeur du parent :

    200px 3 img { max-width: 100%; } 1 2 3 tu es bien taquin ! ça rentre en largeur mais c'est tout déformé verticalement
  34. img { max-width: 100%; height: auto; } 1 2 3

    4 Lorem Elsass Ipsum mitt picon bière munster du ftomi! Ponchour bisame. Bibbeleskaas jetz rossbolla sech choucroute un schwanz geburtstàg, Chinette dû, ìch bier deppfele schiesser. Flammekueche de knèkes Seppele gal! a hopla geburtstàg, alles fraü Chulia Roberts oder knäckes dûû blottkopf. Noch bredele schissabibala, yeuh e schmutz. largeur du parent : 200px l'espace est réservé avant même que l'image ne soit chargée 4 <img src="(chemin)" alt="" width="2000" height="1000"> 1
  35. img { max-width: 100%; height: auto; } 1 2 3

    4 <img src="(chemin)" alt="" width="2000" height="1000"> 1 Lorem Elsass Ipsum mitt picon bière munster du ftomi! Ponchour bisame. Bibbeleskaas jetz rossbolla sech choucroute un schwanz geburtstàg, Chinette dû, ìch bier deppfele schiesser. Flammekueche de knèkes Seppele gal! a hopla geburtstàg, alles fraü Chulia Roberts oder knäckes dûû blottkopf. Noch bredele schissabibala, yeuh e schmutz. image 2000 x 1000px largeur du parent : 200px et hop, pas de Layout Shift ! 4 height: auto permet au navigateur d'appliquer le ratio de l'image quelle que soit sa largeur d'affichage ! width et height indiquent au navigateur le ratio de l'image
  36. <img src="(chemin)" alt="" width="2000" height="1000"> 1 Lorem Elsass Ipsum mitt

    picon bière munster du ftomi! Ponchour bisame. Bibbeleskaas jetz rossbolla sech choucroute un schwanz geburtstàg, Chinette dû, ìch bier deppfele schiesser. Flammekueche de knèkes Seppele gal! a hopla geburtstàg, alles fraü Chulia Roberts oder knäckes dûû blottkopf. Noch bredele schissabibala, yeuh e schmutz. largeur du parent : 200px 4 img { max-width: 100%; height: auto; background: gray; } 1 2 3 4 5 chouette astuce ! la couleur de fond de l'image s'applique même quand l'image n'est pas chargée, couvrant la surface de l'image grâce à son ratio connu du navigateur
  37. Indiquer les dimensions (width et height) dans le HTML pour

    que le navigateur puisse calculer le ratio. Utiliser des formats d'images modernes (webp, avif) max-width: 100% pour que l'image s'adapte en largeur à son conteneur. height: auto pour que le navigateur applique le ratio systématiquement background-color sur l'image pour indiquer visuellement l'espace qui sera occupé quand elle sera chargée (placeholder). Conclusion Layout Shift dûs aux médias
  38. Les images ne sont chargées que si JS est prêt

    Les images ont des hauteurs différentes Bonus track Les carousels 💩 ressource : https://bordermedia.org/2021/12/owl-carousel-cls-cumulative-layout-shift-fix/ Causes de Layout Shifts : min-height sur l'ensemble du carousel height fixe et identique sur les images propriété aspect-ratio Solutions :
  39. body { font-family: SuperPolice, arial, sans-serif; } 1 2 3

    @font-face { font-family: SuperPolice; src: url("superfont.woff2") format("woff2"); } 1 2 3 4 5 font-display: swap; transparent arial SuperPolice
  40. auto font-display: auto; @font-face { 1 font-family: kiwi; 2 src:

    url("kiwi.woff2"); 3 4 } 5 Valeur par défaut. Le navigateur décide de sa stratégie d'affichage : FOUT, FOIT, autre, bref il fait sa vie quand utiliser "auto" ? Jamais ? A priori aucun intérêt d'avoir des comportements différents selon les navigateurs.
  41. block font-display: block; @font-face { 1 font-family: kiwi; 2 src:

    url("kiwi.woff2"); 3 4 } 5 Bloquage volontaire de la police durant 3s. Le contenu est alors invisible, c'est le FOIT. quand utiliser "block" ? Adapté pour les fontes d'icônes, pour éviter les caractères exotiques quand la police n'est pas encore chargée.
  42. swap font-display: swap; @font-face { 1 font-family: kiwi; 2 src:

    url("kiwi.woff2"); 3 4 } 5 Affichage immédiat de la police alternative, puis remplacement quand la police est chargée. C'est le FOUT. quand utiliser "swap" ? Adapté pour tous les contenus textuels mais déclenche forcément un Layout Shift.
  43. fallback font-display: fallback; @font-face { 1 font-family: kiwi; 2 src:

    url("kiwi.woff2"); 3 4 } 5 Comportement un peu passe-partout. On cumule FOIT puis FOUT. quand utiliser "fallback" ?
  44. optional font-display: optional; @font-face { 1 font-family: kiwi; 2 src:

    url("kiwi.woff2"); 3 4 } 5 La police n'est affichée que si elle est immédiatement disponible (déjà dans le cache par exemple). BONUS : elle sera affichée sur la page suivante. quand utiliser "optional" ? Parfait si la police n'est pas absolument nécessaire ou si elle est pré-chargée. Ne crée pas de Layout Shift. 💪
  45. @font-face { font-family: 'Adjusted FredokaOne-Regular'; src: url(FredokaOne-Regular.woff2) format('woff2'); size-adjust: 98%;

    ascent-override: 72%; descent-override: 5%; line-gap-override: 41%; font-display: swap; } h1 { font-family: 'Adjusted FredokaOne-Regular', 'Arial'; } 1 2 3 4 5 6 7 8 9 10 11 12 13 Police principale ajustée
  46. Préchargement avec rel=preload https://web.dev/fetch-priority/ <!-- Dans le <head> après la

    feuille de styles pour ne pas la retarder --> <link rel="preload" as="font" href="kiwi.woff2" type="font/woff2" crossorigin="anonymous"> Prévu pour plein de ressources : surtout fonts et images, mais aussi style, script, audio, vidéo, embed, object, etc
  47. sans rel="preload" HTML CSS font 1 font 2 FOUT /

    FOIT je suis le temps qui passe...
  48. avec rel="preload" HTML CSS font 1 font 2 FOUT /

    FOIT je suis le temps qui passe...
  49. Compresser les fichiers (.woff2) Choisir font-display: optional Éviter les icon-fonts

    Ajustez les polices alternatives Précharger les polices critiques Héberger les polices sur son propre domaine Conclusion Layout Shifts des polices web