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

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

Raphael Goetter
October 05, 2022

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. Layout
    Shifts
    Tu fais du Web et tu
    connais pas les
    ?
    Nan mais...
    📞

    View full-size slide

  2. Hello !
    Je suis Raphaël...
    raphaël goetter

    View full-size slide

  3. 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

    View full-size slide

  4. .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

    View full-size slide

  5. big Merci !
    Merci à Eroan pour son partage de connaissances et
    conseils avisés sur ce sujet
    https://agencewebperformance.fr/

    View full-size slide

  6. À L'AFFICHE

    View full-size slide

  7. Layout
    Shifts
    “ Instabilités graphiques au chargement de
    la page qui dégradent l'expérience utilisateur.
    OK, alors c'est quoi des
    ?

    View full-size slide

  8. Layout
    Shifts
    OK, alors c'est quoi des
    ?
    source : https://web.dev/optimize-cls/

    View full-size slide

  9. 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

    View full-size slide

  10. 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 ?

    View full-size slide

  11. “ Ce sujet à lui seul couvre les thèmes :
    UX, HTML, CSS, Performance... et SEO
    Cumulative Layout Shifts

    View full-size slide

  12. Outils
    Commençons par s'équiper pour
    détecter les Layout Shifts

    View full-size slide

  13. Outils en ligne
    (de notre ami Google)
    https://pagespeed.web.dev/
    (le plus complet à ce jour)
    https://www.webpagetest.org/

    View full-size slide

  14. Outils en local
    (opensource, multibrowsers)
    Lighthouse
    (toi-même tu connais)
    Chrome DevTools
    (extension Firefox et Edge)
    SpeedVitals
    (extension Chrome)
    Web Vitals

    View full-size slide

  15. 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

    View full-size slide

  16. Layout Shifts dûs à la mise en page
    1

    View full-size slide

  17. cas concret
    trois colonnes (avec Grid Layout)
    source : https://http203-playlist.netlify.app/videos/avoiding-layout-shift-by-putting-the-css-in-charge/

    View full-size slide

  18. .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

    View full-size slide

  19. méthode 1
    grid-template-columns
    .container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    }
    1
    2
    3
    4
    je suis le temps qui passe...
    layout shift

    View full-size slide

  20. 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

    View full-size slide

  21. "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

    View full-size slide

  22. 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.
    , float, inline-block, ...
    💩

    View full-size slide

  23. QUIZ !
    alors c'est quoi le mieux ?

    View full-size slide

  24. .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...

    View full-size slide

  25. .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

    View full-size slide

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

    View full-size slide

  27. .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

    View full-size slide

  28. .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

    View full-size slide

  29. .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

    View full-size slide

  30. 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%;

    View full-size slide

  31. 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

    View full-size slide

  32. Layout Shifts dûs aux animations
    2

    View full-size slide

  33. img {
    margin-left: 0;
    transition: 0.5s;
    }
    img:hover {
    margin-left: 100px;
    }
    ooh la jolie transition !

    View full-size slide

  34. 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 !
    👎

    View full-size slide

  35. 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.

    View full-size slide

  36. 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

    View full-size slide

  37. 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 :

    View full-size slide

  38. 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

    View full-size slide

  39. Layout Shifts dûs aux médias
    3

    View full-size slide


  40. Lorem Elsass...
    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...

    View full-size slide


  41. 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

    View full-size slide

  42. 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

    View full-size slide

  43. 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 !

    View full-size slide

  44. width="2000" height="1000">
    1
    image
    2000 x 1000px
    largeur du parent : 200px
    bah forcément ça déborde !
    3

    View full-size slide

  45. 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

    View full-size slide

  46. 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 width="2000" height="1000">
    1

    View full-size slide

  47. img {
    max-width: 100%;
    height: auto;
    }
    1
    2
    3
    4
    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

    View full-size slide

  48. 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

    View full-size slide

  49. 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

    View full-size slide

  50. 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 :

    View full-size slide

  51. Layout Shift dûs aux Polices
    4

    View full-size slide

  52. formats de fichiers modernes

    View full-size slide

  53. @font-face {
    font-family: kiwi;
    src:
    url("/fonts/kiwi.woff2") format("woff2");
    }
    💪
    supporté par 96% de navigateurs

    View full-size slide

  54. font-display

    View full-size slide

  55. 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

    View full-size slide

  56. police alternative "en attendant"
    police invisible "en attendant"
    swap
    block

    View full-size slide

  57. 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.

    View full-size slide

  58. 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.

    View full-size slide

  59. 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.

    View full-size slide

  60. 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" ?

    View full-size slide

  61. 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.
    💪

    View full-size slide

  62. font-display
    compatibilité
    https://caniuse.com/css-font-rendering-controls

    View full-size slide

  63. Police alternative
    ajustée

    View full-size slide

  64. https://screenspan.net/fallback
    (merci à pour la découverte)
    @nhoizey

    View full-size slide

  65. @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

    View full-size slide

  66. size-adjust
    compatibilité
    https://caniuse.com/mdn-css_at-rules_font-face_size-adjust

    View full-size slide

  67. Préchargement

    View full-size slide

  68. Préchargement
    avec rel=preload
    https://web.dev/fetch-priority/

    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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  71. 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

    View full-size slide

  72. Optimizing Web Vitals using
    Lighthouse
    https://web.dev/optimize-vitals-lighthouse/

    View full-size slide

  73. CLS et impact sur le SEO
    https://fr.oncrawl.com/seo-technique/quest-ce-que-le-cumulative-layout-shift/

    View full-size slide

  74. CLS et WordPress
    https://wp-rocket.me/how-to-improve-cls-on-wordpress/

    View full-size slide

  75. Merci !
    Slides sur speakerdeck.com/goetter

    View full-size slide