Développement Web

Optimiser les images et les polices pour le web

13 min de lecture

Ouvrez l’onglet Réseau sur la page d’accueil de la coopérative Niani et triez par taille : en haut de la liste, ce ne sont ni les scripts ni le HTML, mais les images et les polices. Sur la plupart des sites, ces deux familles de ressources représentent à elles seules la majorité du poids téléchargé. Autrement dit, c’est là que se gagne ou se perd la performance — surtout pour un visiteur qui paie ses données au mégaoctet. Ce tutoriel vous apprend à diviser ce poids par deux ou trois sans rien sacrifier à la qualité visuelle.

📍 Guide principal : Core Web Vitals et performance web : le guide — la vue d’ensemble des trois métriques.

🎯 Ce que vous allez apprendre

  • Choisir le bon format d’image moderne (AVIF, WebP) avec un repli sûr.
  • Servir la bonne taille à chaque écran avec srcset et sizes.
  • Compresser vos images sans perte visible, en ligne ou en script.
  • Charger chaque image au bon moment avec loading, fetchpriority et decoding.
  • Héberger et charger vos polices en WOFF2 sans bloquer ni faire sauter le texte.

🛠️ Ce que vous allez construire

Vous reprenez la grille de produits et la police d’affichage de Niani, et vous les optimisez de bout en bout : des images au format moderne, dimensionnées et compressées, chargées intelligemment ; une police autohébergée, légère et préchargée. Le poids de la page fond, le LCP s’améliore et le texte ne saute plus.

Prérequis

  • Des bases en HTML et CSS.
  • Node.js installé si vous voulez automatiser la compression (partie script).
  • Quelques images sources à optimiser (vos photos de produits, par exemple).
  • Niveau : débutant à intermédiaire.
  • ⏱️ Temps estimé : ~50 minutes.

Étape 1 — Choisir le bon format d’image

Le format d’un fichier détermine son poids à qualité égale, et l’écart est énorme. Les formats anciens — JPEG pour les photos, PNG pour les visuels à zones plates — sont dépassés. Les formats modernes compressent bien mieux : le WebP allège typiquement de 25 à 35 % par rapport au JPEG, et l’AVIF va encore plus loin, souvent moitié moins lourd qu’un JPEG de qualité équivalente.

La bonne pratique est de servir l’AVIF en priorité, le WebP en repli, et un JPEG ou PNG en dernier recours pour les très vieux navigateurs. La balise <picture> orchestre ce choix automatiquement : le navigateur prend la première source qu’il sait afficher.

<picture>
  <source type="image/avif" srcset="/img/panier-800.avif">
  <source type="image/webp" srcset="/img/panier-800.webp">
  <img src="/img/panier-800.jpg" alt="Panier tressé"
       width="400" height="300">
</picture>

Le navigateur lit les sources de haut en bas et s’arrête à la première compatible : AVIF sur un navigateur récent, WebP sinon, et la balise <img> finale comme filet de sécurité universel. Vous obtenez le meilleur format possible pour chaque visiteur, sans rien casser pour personne.

Point d’étape — Vos images principales sont servies en AVIF avec repli WebP et JPEG. Comparez le poids dans l’onglet Réseau : il devrait avoir fondu.

Étape 2 — Servir la bonne taille à chaque écran

Un format moderne ne suffit pas si vous envoyez une image de 1600 pixels de large à un téléphone qui n’en affiche que 400. Le navigateur la réduit à l’affichage, mais a quand même téléchargé tous ces pixels inutiles. La solution est de fournir plusieurs tailles et de laisser le navigateur choisir, grâce aux attributs srcset et sizes.

<picture>
  <source type="image/avif"
          srcset="/img/panier-400.avif 400w,
                  /img/panier-800.avif 800w,
                  /img/panier-1200.avif 1200w"
          sizes="(max-width: 600px) 100vw, 400px">
  <img src="/img/panier-800.jpg" alt="Panier tressé"
       width="400" height="300">
</picture>

Décortiquons. Le srcset liste les variantes avec leur largeur réelle en pixels (le suffixe w). Le sizes décrit l’espace que l’image occupera : ici, toute la largeur de l’écran en dessous de 600 pixels, et 400 pixels au-delà. Le navigateur combine ces deux informations avec la densité de l’écran et télécharge la variante la plus adaptée — souvent la plus petite qui reste nette.

Sur une grille de produits, l’effet est cumulatif : douze vignettes servies en 400 pixels au lieu de 1200, c’est un tiers du poids, et un LCP nettement meilleur si l’une d’elles est l’élément principal.

Point d’étape — Vos images existent en plusieurs tailles et le navigateur choisit la bonne. Sur un écran mobile simulé, il télécharge bien la petite variante.

Étape 3 — Compresser sans dégrader

Même au bon format et à la bonne taille, une image peut rester trop lourde si elle est exportée à pleine qualité. La compression réduit ce poids en supprimant des détails imperceptibles à l’œil. Pour quelques images, l’outil web gratuit Squoosh permet de comparer côte à côte l’original et le compressé, et de descendre la qualité jusqu’au point juste avant que la dégradation ne devienne visible.

Pour automatiser sur un catalogue entier, la bibliothèque sharp (Node.js) convertit et compresse en quelques lignes. C’est le réflexe à adopter dès que vous gérez plus d’une poignée d’images.

import sharp from 'sharp';

// Genere une version AVIF 800px compressee depuis une photo source
await sharp('sources/panier.jpg')
  .resize(800)
  .avif({ quality: 50 })
  .toFile('img/panier-800.avif');

Une qualité AVIF autour de 50 donne en général un excellent compromis : le fichier est très léger et la photo reste nette. Lancez la conversion sur toutes vos tailles et tous vos formats avec une boucle, et votre dossier d’images est prêt. Vérifiez toujours le résultat à l’œil sur une ou deux images avant de généraliser.

Point d’étape — Vos images sont compressées au point optimal. Une vignette de produit devrait peser quelques dizaines de kilo-octets, pas plusieurs centaines.

Étape 4 — Charger chaque image au bon moment

Toutes les images d’une page n’ont pas la même urgence. La bannière visible au chargement doit arriver tout de suite ; les vignettes situées tout en bas peuvent attendre que l’utilisateur défile jusqu’à elles. Trois attributs règlent ce tempo.

loading="lazy" diffère le chargement des images sous la ligne de flottaison : le navigateur ne les télécharge qu’à l’approche du défilement. Attention : ne jamais le mettre sur l’image LCP, sous peine de la retarder volontairement. fetchpriority="high" fait l’inverse pour l’image principale, et decoding="async" autorise le navigateur à décoder l’image sans bloquer le reste de l’affichage.

<!-- Bannière principale : prioritaire, jamais differee -->
<img src="/img/banniere.avif" alt="Coopérative Niani"
     fetchpriority="high" decoding="async"
     width="1200" height="600">

<!-- Vignette plus bas : chargement differe -->
<img src="/img/panier-400.avif" alt="Panier tressé"
     loading="lazy" decoding="async"
     width="400" height="300">

Cette répartition fait que le navigateur consacre sa bande passante d’abord à ce que l’utilisateur voit, puis au reste à mesure des besoins. Sur un long catalogue, le chargement différé économise des centaines de kilo-octets que l’utilisateur ne verra peut-être jamais.

Point d’étape — Votre image principale est prioritaire, vos images du bas sont différées. L’onglet Réseau montre qu’elles ne se chargent qu’au défilement.

Étape 5 — Choisir et héberger vos polices

Passons à l’autre grande source de poids : les polices. Trois décisions font la différence. D’abord le format : le WOFF2 est le format de police le plus compressé et il est universellement supporté ; n’embarquez rien d’autre. Ensuite l’hébergement : autohéberger vos polices plutôt que de les charger depuis un service tiers évite une connexion supplémentaire à un autre domaine, et vous garde maître du chargement. Enfin le sous-ensemble : si votre site est en français, inutile d’embarquer les caractères cyrilliques ou asiatiques ; un sous-ensemble latin allège fortement le fichier.

@font-face {
  font-family: 'Niani Display';
  src: url('/fonts/niani-display.woff2') format('woff2');
  font-weight: 400 700;          /* une police variable couvre plusieurs graisses */
  font-display: swap;
  unicode-range: U+0000-00FF;    /* sous-ensemble latin */
}

Notez font-weight: 400 700 : c’est une police variable, un seul fichier qui contient toutes les graisses du regular au gras. Cela remplace trois ou quatre fichiers séparés par un seul, souvent plus léger au total. La propriété unicode-range indique au navigateur quels caractères ce fichier couvre, pour qu’il ne le télécharge que s’il en a besoin.

Point d’étape — Votre police est en WOFF2, autohébergée, et limitée aux caractères utiles. Son poids devrait être de quelques dizaines de kilo-octets.

Étape 6 — Charger les polices sans bloquer ni décaler

Une police mal chargée provoque deux maux : du texte invisible le temps qu’elle arrive, ou un saut de mise en page au moment du remplacement. On les évite avec un trio de réglages.

D’abord, précharger la police critique pour qu’elle parte tôt. Ensuite, font-display: swap affiche immédiatement le texte avec une police de secours, puis bascule sur la vôtre dès qu’elle est prête — le texte est toujours lisible. Enfin, pour que ce basculement ne provoque pas de décalage, on ajuste les métriques de la police de secours, comme vu dans le tutoriel sur le CLS.

<!-- Dans le <head> : la police critique part au plus tot -->
<link rel="preload" href="/fonts/niani-display.woff2"
      as="font" type="font/woff2" crossorigin>

L’attribut crossorigin est obligatoire sur le préchargement d’une police, même autohébergée, sinon le navigateur télécharge le fichier deux fois. Avec ce trio — précharger, afficher en secours, ajuster les métriques — votre police arrive vite, le texte reste lisible dès la première image, et rien ne saute. Si vous préférez la stabilité absolue à l’usage garanti de votre police sur les connexions très lentes, font-display: optional est une alternative : le navigateur n’utilise votre police que si elle arrive presque instantanément.

Point d’étape — Votre police est préchargée et le texte ne saute plus à son arrivée. Dans l’onglet Réseau, elle n’est téléchargée qu’une seule fois.

Étape 7 — Vérification finale

Rechargez la page et comparez le poids total dans l’onglet Réseau avec votre point de départ. Entre les formats modernes, le bon dimensionnement, la compression et le sous-ensemble de police, il n’est pas rare de diviser le poids des médias par deux ou trois. Relancez ensuite Lighthouse : le LCP s’améliore (image principale plus légère), le CLS reste à zéro (dimensions réservées, police ajustée), et le score grimpe.

La page Niani charge désormais ses visuels et son texte avec un budget de données minimal, tout en restant nette et stable. Il ne reste plus qu’une grande source de poids à dompter : le JavaScript, objet du dernier tutoriel de la série.

🐞 Pièges fréquents

Symptôme Cause probable Correctif
L’image principale se charge tard loading="lazy" appliqué à l’élément LCP Retirer le chargement différé sur la bannière, le réserver aux images du bas
La police est téléchargée deux fois crossorigin manquant sur le préchargement Ajouter crossorigin à la balise de préchargement
L’AVIF ne s’affiche pas chez certains visiteurs Navigateur trop ancien sans repli Toujours fournir un repli WebP ou JPEG dans <picture>
Le navigateur télécharge la grande image sur mobile sizes mal renseigné ou absent Décrire précisément l’espace occupé dans sizes

🌍 Réalités du terrain

Pour un public ouest-africain, l’optimisation des images et des polices n’est pas un détail technique : c’est ce qui rend un site utilisable sur une connexion fragile et un forfait compté. À Bamako, Lomé ou Conakry, une page de catalogue qui passe de 3 mégaoctets à 900 kilo-octets, c’est la différence entre une visite qui aboutit et un abandon avant l’affichage. Chaque image en AVIF plutôt qu’en JPEG, chaque police sous-ensemblée, ce sont des secondes gagnées et des francs CFA économisés pour le visiteur.

Un conseil pratique : si vous manquez de temps pour automatiser, traitez en priorité les images les plus visibles — bannière, premières vignettes — et la police principale. Ces quelques fichiers représentent souvent l’essentiel du poids ressenti au chargement. Le reste peut suivre progressivement.

✅ Récapitulatif

Vous savez désormais alléger les deux familles de ressources les plus lourdes. Pour les images : format moderne avec repli, bonne taille via srcset, compression maîtrisée, et chargement au bon moment. Pour les polices : WOFF2 autohébergé et sous-ensemblé, préchargement, affichage en secours et métriques ajustées. C’est l’optimisation la plus rentable de toute la performance web, car elle agit directement sur le poids téléchargé.

🧾 Aide-mémoire

Élément Rôle
<picture> AVIF → WebP → JPEG Servir le meilleur format avec repli
srcset + sizes Servir la bonne taille à chaque écran
sharp / Squoosh Compresser et convertir les images
loading="lazy" Différer les images sous la ligne de flottaison
WOFF2 + sous-ensemble + variable Polices légères
rel="preload" as="font" crossorigin Charger la police critique tôt, une seule fois
font-display: swap Texte lisible dès le départ

💪 À vous de jouer

Prenez la plus grosse image de votre page, convertissez-la en AVIF avec Squoosh ou sharp, servez-la via <picture> et comparez le poids avant/après dans l’onglet Réseau.

Voir une piste de solution

Une photo de bannière de 850 Ko en JPEG tombe souvent autour de 200 à 300 Ko en WebP et 120 à 180 Ko en AVIF, sans différence visible à l’écran. En ajoutant srcset pour servir une variante plus petite sur mobile, la version réellement téléchargée par un téléphone peut descendre sous 80 Ko. C’est un gain direct sur le LCP et sur la facture de données du visiteur.

Dans la même série

  • Optimiser le LCP — l’image principale conditionne directement cette métrique.
  • Optimiser le CLS — réserver l’espace et ajuster les polices pour ne plus sauter.

Pour aller plus loin

FAQ

AVIF ou WebP : lequel choisir ?
Les deux, dans cet ordre. L’AVIF compresse mieux mais le WebP est un repli plus largement supporté. Avec <picture>, le navigateur prend l’AVIF s’il le peut, sinon le WebP, sinon le JPEG. Vous n’avez pas à choisir pour l’utilisateur.

Faut-il abandonner Google Fonts ?
Pas obligatoirement, mais autohéberger vos polices supprime une connexion à un domaine tiers et vous laisse maîtriser le préchargement et le sous-ensemble. Pour une performance fine, l’autohébergement en WOFF2 est généralement préférable.

Le chargement différé peut-il nuire au référencement ?
Non, l’attribut loading="lazy" natif est compris par les moteurs. Le seul piège est de l’appliquer à l’image principale (LCP) : là, il dégrade la performance. Réservez-le aux images situées sous la ligne de flottaison.

Partager