Optimiser les images de son application web
40% du poids d'une page vient des images. 4 points de contrôle pour ne pas en faire le maillon faible de votre app.
La performance n'est pas un sujet d'optimisation a posteriori. C'est une contrainte à intégrer dès les premières maquettes, surtout pour les images. D'après le Web Almanac 2024, elles représentent environ 40% du poids médian d'une page (900 Ko sur 2,3 Mo sur mobile). Et sur mobile, 68% des pages ont une image comme élément LCP (Web Almanac 2024). Le temps de chargement perçu par vos utilisateurs est donc, 2 fois sur 3, le temps de chargement d'une image.
Pourtant, côté adoption, c'est la misère : seulement 42% des pages mobile utilisent srcset et 55% des images ont un attribut alt renseigné. Il y a encore une grosse marge.
Aujourd'hui, je vous partage la méthode que j'applique sur mes projets pour traquer et corriger les images mal optimisées.
Diagnostiquer avant de coder
Avant de toucher au code, il faut mesurer. Deux outils suffisent dans 95% des cas.
Lighthouse, en navigation privée (pour éviter les biais des extensions), donne un score global et pointe les premiers coupables. Les poids des métriques sont :
| Métrique | Poids | Ce qu'elle mesure |
|---|---|---|
| TBT | 30% | Temps total de blocage du main thread |
| LCP | 25% | Temps d'affichage du plus grand élément |
| CLS | 25% | Stabilité visuelle pendant le chargement |
| FCP | 10% | Temps d'affichage du premier contenu |
| SI | 10% | Vitesse perçue de rendu |
💡 Le Lighthouse Scoring Calculator permet de simuler l'impact d'une amélioration avant de s'y mettre. Très utile pour prioriser un chantier.
WebPageTest complète Lighthouse avec une visualisation "cascade" du chargement. C'est là qu'on identifie précisément quelle image charge trop tôt, trop tard, ou depuis un serveur trop lent.
4 questions à se poser pour chaque image
1. L'image est-elle à la bonne taille ?
Compression. La règle du pouce : une qualité JPEG à 75% est rarement distinguable de l'original à l'œil nu, pour un fichier typiquement 3 à 4 fois plus léger. Deux approches :
- Sans perte (lossless) : supprime les métadonnées et données redondantes sans altérer la qualité
- Avec perte (lossy) : réduit la taille en dégradant la qualité de manière contrôlée
Format. Chaque format a son terrain :
| Format | Usage | Pourquoi |
|---|---|---|
| JPEG | Photos | Compression lossy éprouvée, supporté partout |
| PNG | Graphiques avec transparence | Lossless, bon pour logos et captures |
| SVG | Icônes, logos | Vectoriel, zoom sans perte, très léger |
| WebP | Remplaçant moderne | ~30% plus léger qu'un JPEG équivalent |
| AVIF | Next-gen | Encore plus léger que WebP, encodage plus lent |
Le Base64 inline n'a sa place que pour des images minuscules (< 1 KB). Au-dessus, l'overhead de 33% de l'encodage annule tout bénéfice du "moins de requêtes".
Responsive. L'erreur classique : charger la même image 1200px de large sur un écran 375px. Le srcset règle ça :
<img
srcset="image-400.webp 400w, image-800.webp 800w, image-1200.webp 1200w"
sizes="(max-width: 600px) 400px, (max-width: 900px) 800px, 1200px"
src="image-1200.webp"
alt="Description pertinente pour le SEO et l'accessibilité"
/>Bien configuré, on divise facilement le poids par 3 sur mobile.
2. L'image charge-t-elle au bon moment ?
Par défaut, le navigateur télécharge toutes les images dès le parsing du HTML. C'est rarement ce qu'on veut.
Lazy loading pour tout ce qui est sous la ligne de flottaison :
<img src="image.jpg" loading="lazy" alt="..." />Priorité explicite pour les images critiques au LCP (hero, bannière) :
<link rel="preload" as="image" href="hero.webp" />
<img src="hero.webp" fetchpriority="high" alt="..." />Pour un carousel, seule la première slide doit être prioritaire. Les suivantes peuvent, et doivent, attendre :
<img src="slide-1.jpg" fetchpriority="high" alt="..." />
<img src="slide-2.jpg" fetchpriority="low" loading="lazy" alt="..." />
<img src="slide-3.jpg" fetchpriority="low" loading="lazy" alt="..." />3. L'image arrive-t-elle rapidement pour tous ?
Les images sont des assets statiques. Deux leviers :
- Cache navigateur :
Cache-Control: public, max-age=15552000, immutable(180 jours). Leimmutableévite la revalidation tant que l'URL ne change pas. Si vous modifiez une image, changez son URL (un hash dans le nom de fichier est le pattern le plus simple). - CDN pour la distribution géographique. Cloudflare, Vercel, TwicPics, Cloudinary, Imgix font tous le travail. Le bonus avec les services spécialisés (TwicPics, Cloudinary) : génération automatique des variantes responsive et conversion à la volée vers WebP/AVIF selon le navigateur du visiteur.
4. L'image est-elle référencée correctement ?
Les crawlers ne "voient" pas les images. Ils lisent leur contexte. Deux attributs font 90% du travail :
altdescriptif (pasimage1.jpg, pas vide non plus)- nom de fichier lisible (
sunset-beach-vacation.webpplutôt queIMG_1234.webp)
Pour les images importantes (illustrations d'article, produits e-commerce), un JSON-LD ImageObject renforce le signal :
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "ImageObject",
"caption": "Sunset Beach Vacation",
"image": "https://example.com/media/sunset-beach-vacation.webp",
"description": "Sunset at the beach while on vacation"
}
</script>Laisser le framework faire le sale boulot
Tout ce qu'on vient de voir peut être automatisé. Les composants Image de Next.js ou NuxtImg font par défaut :
- conversion WebP/AVIF à la volée selon le navigateur
- génération des variantes responsive
- lazy loading (sauf si
priorityest activé pour l'image LCP) - prévention du CLS via les attributs
width/heightobligatoires
import Image from 'next/image';
<Image
src="/sunset.jpg"
alt="Coucher de soleil sur la plage"
width={1200}
height={800}
priority // uniquement pour l'image LCP
quality={75}
placeholder="blur"
/>;Si vous êtes sur un framework moderne, commencer par ce composant élimine la grande majorité des problèmes sans effort. C'est souvent la première chose que je fais en arrivant sur un projet existant.
Ce que j'ai compris
💡 L'optimisation d'images est un des rares chantiers où l'effort est faible et l'impact mesurable énorme. Passer 2h à auditer les images d'un site rapporte souvent plus qu'une semaine à optimiser du JavaScript.
Et c'est un chantier qui se paye en continu : chaque nouvelle image ajoutée sans réflexion annule une partie du travail précédent. Autant imposer les bons réflexes dès le départ. Comme pour la qualité de code, il est bien plus coûteux de rattraper a posteriori.