Optimiser les
Images pour le Web

Vectoriel ou Bitmap ?

Formes simples dont on mémorise les dimensions, les points, les couleurs.
Très léger, se compresse bien en zip.

  • SVG

Mémorisation pixel par pixel.

Poids conséquent.

  • GIF
  • JPEG
  • PNG
  • WEBP
  • AVIF
  • JPEG-XL
  • ...

Tiens, ça mériterait un sujet dédié…

gif

Steve Wilhite
inventeur du GIF
(en gif)

et sinon, côté Bitmap ?

jpeg

logo officiel de JPEG

png

bah, non rien

jpeg

progressif

jpeg

optimisation

Mozilla a lancé son propre projet MozJpeg pour (re)concurrencer WebP

png

entrelacé

avec entrelacement

sans entrelacement

le Bitmap moderne

webp

logo officiel Webp

webp

  • 24 bits (au lieu de 8 pour GIF)
  • Lossless (sans perte de qualité) ou lossy (avec) au choix
  • Transparence alpha
  • Développé par Google à partir de VP8 (algorithme vidéo de WebM)
  • Support EXIF, profil de couleurs ICC
  • Animations
  • Jusqu’à 30-50% plus léger par rapport à JPEG ou PNG

👍🏻

avantages

webp

  • développé par Google (mais open source)

inconvénients

👎🏻

webp

comparatif

PNG (original) : 1.8 Mo

JPEG (MozJPG) : 71 Ko

Webp : 53 Ko

webp

comparatif png transparent

webp

compatibilité

avif (av1)

logo officiel av1

avif

👍🏻

avantages

  • Développé par l’Alliance for Open Media http://aomedia.org/ pour être open-source et royalty-free
  • Dérive du codec vidéo AV1 (libre contrairement à H.264/265/HEC)
  • Lossless ou lossy
  • Transparence
  • HDR
  • Animations 

avif

inconvénients

  • Supporté depuis août 2020 par Chrome, plus récemment par Firefox, Safari et Edge
  • Pas de progressif

👎🏻

avif

avif

avif

comparatif

PNG (original) : 1.8 Mo

JPEG (MozJPG) : 71 Ko

Webp : 53 Ko

Avif : 25 Ko

avif

compatibilité

avif

performances

jpeg XL (.jxl)

jpeg XL (.jxl)

compatibilité

Éviter les Layout Shifts

Important pour l'UX (et Google)

<img src="(chemin)" alt="">
<p>Lorem Elsass...</p>

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

<img src="(chemin)" alt="">

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

<img src="(chemin)" alt="" width="200" height="100">

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

<img src="(chemin)" alt="" width="200" height="100">

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 !

<img src="(chemin)" alt="" width="2000" height="1000">

image

2000 x 1000px

largeur du parent : 200px

bah forcément ça déborde !

3

<img src="(chemin)" alt="" width="2000" height="1000">

largeur du parent : 200px

tu es bien taquin !
ça rentre en largeur mais c'est tout déformé verticalement

3

img {
  max-width: 100%;
}

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

Ah oui là on est bien !
Et l'espace est bien réservé avant même que l'image ne soit chargée

4

<img src="(chemin)" alt="" width="2000" height="1000">
img {
  max-width: 100%;
  height: auto;
}
<img src="(chemin)" alt="" width="2000" height="1000">

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 !

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

width et height indiquent au navigateur le ratio de l'image

<img src="(chemin)" alt="" width="2000" height="1000">

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

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

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

chouette astuce !

<img src="(chemin)" alt="" width="1024" height="768">
img {
  max-width: 100%;
  height: auto;
  background: gray;
}

HTML :

  • width et height originelles pour  indiquer le ratio au navigateur

Conclusion

Images et Layout Shifts

CSS :

  • max-width: 100% pour s'assurer d'une largeur fluide
  • height: auto pour contraindre le ratio
  • background pour servir de "placeholder"

Ha ! Il y en a un peu plus

je vous le mets ?

On charge paresseusement

avec loading="lazy"

<img src="kiwi.webp" loading="lazy" 
     width="..." height="..." alt="...">
  • eager : l'image est chargée immédiatement, qu'elle soit située dans ou hors de la fenêtre visible (valeur par défaut),
  • lazy : le chargement est retardé jusqu'à ce que l'usager scrolle et s'approche du bas de la fenêtre du navigateur.

On décode  paresseusement

decoding="async"

<img src="kiwi.webp" decoding="async" loading="lazy"
     width="..." height="..." alt="...">
  • sync : décode l'image de manière synchrone
  • async : décode l'image de manière asynchrone (parallélise les threads du CPU)
  • auto (par défaut) : laisse le navigateur décider

On précharge

avec rel="preload"

<!-- Dans le <head> après
     la feuille de styles pour ne pas la bloquer -->
<link rel="preload" as="image" href="hero.webp">

Prévu pour plein de ressources : surtout fonts et images, mais aussi style, script, audio, vidéo, embed, object, etc

on suppose que cette image est critique et doit s'afficher dès que possible

On priorise

avec fetchpriority

<!-- Cette image de fond critique 
     est hautement prioritaire -->
<link rel="preload" as="image" href="hero.webp" fetchpriority="high">

exemple pour un carousel :

<ul class="carousel">
  <img src="img/carousel-1.jpg" fetchpriority="high">
  <img src="img/carousel-2.jpg" fetchpriority="low">
  <img src="img/carousel-3.jpg" fetchpriority="low">
  <img src="img/carousel-4.jpg" fetchpriority="low">
</ul>
  • Utiliser des formats d'images modernes (avif, webp)
  • Compresser à 70-80%
  • Indiquer les dimensions (width et height) dans le HTML.
  • max-width: 100% et height: auto
  • Afficher une couleur de fond en guise de "placeholder"
  • loading="lazy" sur l'image pour ne la charger que si nécessaire (scroll)
  • decoding="async" pour libérer le CPU
  • En bonus : rel="preload", fetchpriority="high"

Conclusion générale

optimisation des images

implémentation

pour le Web

<picture>

<picture>
  <source type="image/avif" srcset="kiwi.avif">
  <img src="kiwi.webp" alt="kiwi" decoding="async" loading="lazy" 
       width="3000" height="2000">
</picture>

type permet de servir des format d'images différents selon la compatibilité navigateur

#old
=
jpg

#new
=
avif/webp

👍🏻

Ressources

Quetsche

Squoosh

ImageMagick

magick -quality 70 kiwi.jpg kiwi.jpg
magick -quality 70 kiwi.jpg kiwi.webp
magick -quality 70 kiwi.jpg kiwi.avif