Optimisation des images Next.js pour Core Web Vitals en 2026
Optimisation des images Next.js pour Core Web Vitals en 2026
J'ai passé les quatre dernières années à optimiser les images dans les applications Next.js, et je vais être honnête -- le paysage en 2026 ne ressemble en rien à celui d'avant le lancement de next/image. Les seuils Core Web Vitals de Google se sont resserrés, de nouveaux formats d'image ont mûri, et le composant next/image lui-même a connu plusieurs réécritures. Si vos images sont toujours configurées comme elles l'étaient en 2023, vous laissez des performances (et des classements) sur la table.
Ce n'est pas une reformulation de la documentation Next.js. C'est ce que j'ai appris en déployant des dizaines de sites en production où les scores LCP comptent vraiment -- où une différence de 200ms dans le chargement des images signifiait la différence entre la première et la troisième page.
Table des matières
- Core Web Vitals en 2026 : Qu'est-ce qui a changé
- Comment next/image fonctionne réellement en coulisse
- Le problème LCP : Pourquoi votre image héros tue votre score
- Les guerres de format : AVIF vs WebP vs JPEG XL en 2026
- Images responsives bien faites
- Stratégies d'optimisation CDN et Edge
- Mesurer ce qui compte : Outils et benchmarks
- Techniques avancées qui font vraiment la différence
- Erreurs courantes que je vois à chaque audit
- FAQ

Core Web Vitals en 2026 : Qu'est-ce qui a changé
Google a mis à jour les seuils Core Web Vitals fin 2025, et les changements n'étaient pas triviaux. Voici où nous en sommes :
| Métrique | Seuil « Bon » 2023 | Seuil « Bon » 2026 | Ce qu'il mesure |
|---|---|---|---|
| LCP | ≤ 2,5s | ≤ 2,0s | Largest Contentful Paint |
| INP | ≤ 200ms | ≤ 150ms | Interaction to Next Paint |
| CLS | ≤ 0,1 | ≤ 0,1 | Cumulative Layout Shift |
| TTFB | N/A (pas un CWV) | Informellement ≤ 600ms | Time to First Byte |
La baisse du seuil LCP de 2,5s à 2,0s est celle qui a le plus affecté les sites riches en images. Une demi-seconde ne semble pas grand-chose jusqu'à ce que vous réalisiez que pour 60%+ des pages, l'élément LCP est une image. Généralement une image héros, une photo produit, ou une vignette d'article à la une.
Le remplacement d'INP par FID était déjà en vigueur, mais le seuil resserré de 150ms signifie que les gros bundles JavaScript -- y compris les scripts de lazy-loading d'images mal configurés -- peuvent tuer vos scores d'interactivité.
CLS est resté le même, ce qui est une bonne nouvelle. Mais les images restent la cause numéro un de décalages de mise en page lorsqu'elles n'ont pas de dimensions explicites.
Pourquoi c'est important pour Next.js spécifiquement
Les applications Next.js ont tendance à être lourdes en JavaScript. Vous livrez React, vous livrez le code du framework, et si vous ne faites pas attention, vous livrez aussi la logique d'optimisation des images côté client. La combinaison d'un budget LCP plus strict et de la surcharge JS d'une application React signifie que vous avez moins de marge d'erreur qu'un site HTML statique.
C'est exactement pourquoi nous nous concentrons fortement sur le développement Next.js -- le framework vous donne des outils incroyables, mais seulement si vous savez comment les configurer.
Comment next/image fonctionne réellement en coulisse
Démystifions ce qui se passe lorsque vous utilisez <Image /> depuis next/image. Comprendre le pipeline vous aide à prendre de meilleures décisions d'optimisation.
Le flux de requête
- Temps de build : Next.js génère HTML avec une balise
<img>qui pointe vers/_next/image?url=...&w=...&q=... - Première requête : L'API d'optimisation d'image Next.js reçoit la requête, récupère l'image originale, la redimensionne, convertit le format, et met en cache le résultat
- Requêtes ultérieures : La version en cache est servie directement
Dans Next.js 15 (l'actuel stable début 2026), l'optimiseur d'image utilise sharp par défaut dans les environnements Node.js. Sur Vercel, il utilise leur service d'optimisation d'image basé sur les edges. Sur d'autres plateformes, il revient à sharp ou squoosh selon votre configuration.
// Utilisation basique -- mais beaucoup se passe derrière cela
import Image from 'next/image';
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Product hero shot"
width={1200}
height={630}
priority
quality={80}
/>
);
}
Cette prop priority fait plus que vous ne le pensez. Elle ajoute fetchpriority="high" au HTML, désactive le lazy loading, et génère une balise <link> de préchargement dans le <head>. Nous reviendrons sur pourquoi c'est important pour LCP.
La config que la plupart des gens ne touchent jamais
Votre next.config.js (ou next.config.ts si vous avez migré) a une clé images qui contrôle tout :
// next.config.js
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
minimumCacheTTL: 31536000, // 1 an en secondes
dangerouslyAllowSVG: false,
remotePatterns: [
{
protocol: 'https',
hostname: 'your-cms.com',
pathname: '/assets/**',
},
],
},
};
L'ordre du tableau formats compte. Next.js essaiera d'abord AVIF, puis revient à WebP. L'encodage AVIF est plus lent mais produit des fichiers plus petits -- ce compromis vaut la peine d'être compris.
Le problème LCP : Pourquoi votre image héros tue votre score
Voici le scénario que je vois à presque chaque audit : une belle image héros, au-dessus du pli, qui prend 3+ secondes à afficher. Le développeur a utilisé next/image, a pensé avoir terminé, et est passé à autre chose. Mais le score est terrible.
Les coupables habituels :
1. Oubli de la prop `priority`
Par défaut, next/image lazy-charge tout. C'est super pour les images sous le pli mais catastrophique pour votre élément LCP. Sans priority, le navigateur découvre l'image tard, après l'hydratation de JavaScript et l'activation de l'observateur d'intersection.
// ❌ Cela lazy-charge votre image LCP
<Image src="/hero.jpg" alt="Hero" width={1200} height={630} />
// ✅ Cela la précharge
<Image src="/hero.jpg" alt="Hero" width={1200} height={630} priority />
2. Sur-compression avec des valeurs de qualité basses
J'ai vu des équipes régler quality={50} pensant plus petit = plus rapide. Mais si l'image est floue, l'algorithme LCP de Chrome doit quand même attendre qu'elle s'affiche complètement. Et sur les écrans haute résolution, une qualité en dessous de 70 déclenche souvent des artefacts visibles qui donnent à la conception un air bon marché.
Ma règle de base : qualité 75-85 pour les photos, qualité 90+ pour les images avec du texte ou des bords nets.
3. Ne pas utiliser correctement `sizes`
L'attribut sizes indique au navigateur quelle largeur d'image demander avant que CSS ne soit analysé. Sans cela, Next.js utilise par défaut 100vw, ce qui signifie que les appareils mobiles téléchargent des images de taille desktop.
<Image
src="/hero.jpg"
alt="Hero"
fill
priority
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px"
/>
Ce seul changement de prop m'a donné les plus grosses améliorations LCP -- parfois 400-800ms sur mobile.

Les guerres de format : AVIF vs WebP vs JPEG XL en 2026
Le paysage des formats s'est considérablement stabilisé. Voici où nous en sommes :
| Format | Support navigateur (2026) | Compression | Vitesse d'encodage | Meilleur pour |
|---|---|---|---|---|
| AVIF | ~95% mondialement | Excellent (30-50% plus petit que WebP) | Lent | Photos, images héros |
| WebP | ~98% mondialement | Bon (25-35% plus petit que JPEG) | Rapide | Usage général |
| JPEG XL | ~45% (Chrome l'a supprimé) | Excellent | Moyen | Non recommandé pour le web |
| JPEG | Universel | Baseline | Rapide | Fallback seulement |
| PNG | Universel | Mauvais pour les photos | Rapide | Transparence, captures d'écran |
JPEG XL avait une spécification prometteuse, mais la décision de Chrome de le supprimer fin 2023 l'a effectivement tué pour l'usage web. Safari a ajouté le support, Firefox a un support partiel, mais vous ne pouvez pas vous y fier.
Ma recommandation : Réglez formats: ['image/avif', 'image/webp'] et oubliez-le. Next.js gère automatiquement la négociation de contenu via l'en-tête Accept.
Le coût de l'encodage AVIF
Voici quelque chose que la documentation n'emphasize pas assez : l'encodage AVIF est intensif en CPU. Sur une première requête à votre serveur Next.js, l'encodage d'une image AVIF 1200px peut prendre 2-5 secondes sur un serveur modeste. Ce premier visiteur mange le coût.
Stratégies pour atténuer cela :
- Pré-générer au moment du build en utilisant
next exportou des scripts de build personnalisés - Utiliser un CDN avec optimisation d'image intégrée (Cloudflare Images, Imgix, Cloudinary)
- Réchauffer votre cache après le déploiement avec un script qui accède à tous les URL d'images critiques
# Script simple de réchauffement du cache
#!/bin/bash
URLs=("https://yoursite.com/_next/image?url=%2Fhero.jpg&w=1200&q=80"
"https://yoursite.com/_next/image?url=%2Fhero.jpg&w=750&q=80")
for url in "${URLs[@]}"; do
curl -s -o /dev/null -H "Accept: image/avif,image/webp" "$url"
echo "Warmed: $url"
done
Images responsives bien faites
Les images responsives dans Next.js ne sont pas difficiles, mais elles nécessitent de comprendre comment deviceSizes, imageSizes, et la prop sizes fonctionnent ensemble.
Le modèle de mise en page `fill`
Pour les images où vous ne connaissez pas le rapport d'aspect au moment du build (contenu CMS, uploads utilisateur), utilisez la prop fill :
<div className="relative aspect-[16/9] w-full">
<Image
src={post.featuredImage}
alt={post.title}
fill
className="object-cover"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</div>
Le div parent avec positionnement relative et un rapport d'aspect est critique. Sans cela, les images fill s'effondrent à une hauteur zéro et vous obtenez un score CLS qui vous fera grimacer.
Direction artistique avec ``
Parfois vous avez besoin de cultures différentes pour différentes tailles d'écran. next/image ne supporte pas nativement <picture>, mais vous pouvez contourner cela :
// Contournement de direction artistique
export function ResponsiveHero({ mobileSrc, desktopSrc, alt }) {
return (
<>
<div className="block md:hidden relative aspect-[9/16] w-full">
<Image src={mobileSrc} alt={alt} fill priority sizes="100vw" />
</div>
<div className="hidden md:block relative aspect-[16/9] w-full">
<Image src={desktopSrc} alt={alt} fill priority sizes="100vw" />
</div>
</>
);
}
Oui, cela télécharge le HTML des deux images, mais une seule s'affiche, et l'image cachée ne se chargera pas grâce aux par défauts du lazy loading (vous appliqueriez priority seulement à celle correspondant au viewport).
Stratégies d'optimisation CDN et Edge
Si vous auto-hébergez Next.js (et beaucoup d'équipes le font), vous avez besoin d'une stratégie CDN pour les images.
Option 1 : Laisser Vercel le gérer
L'optimisation d'image Vercel s'exécute sur les edges. Pour la plupart des projets, c'est le chemin le plus facile. Depuis 2026, le plan Pro Vercel inclut 5 000 images source avec optimisation, avec images supplémentaires à 5$ pour 1 000. Les plans Enterprise ont une tarification personnalisée.
Option 2 : Service d'optimisation d'image externe
Cloudinary, Imgix, et Cloudflare Images fonctionnent tous avec Next.js via la prop loader ou un loader personnalisé :
// next.config.js avec Cloudinary
module.exports = {
images: {
loader: 'custom',
loaderFile: './lib/cloudinary-loader.js',
},
};
// lib/cloudinary-loader.js
export default function cloudinaryLoader({ src, width, quality }) {
const params = [
`w_${width}`,
`q_${quality || 'auto'}`,
'f_auto',
'c_limit',
];
return `https://res.cloudinary.com/your-cloud/image/upload/${params.join(',')}${src}`;
}
| Service | Niveau gratuit | Tarification Pro (2026) | Nœuds Edge | Support AVIF |
|---|---|---|---|---|
| Cloudinary | 25 crédits/mois | 89$/mois (25GB) | 60+ | Oui |
| Imgix | Aucun | 100$/mois (100GB) | Global | Oui |
| Cloudflare Images | Aucun | 5$/mois (100K variantes) | 310+ | Oui |
| Vercel (intégré) | 1 000 images (Hobby) | Inclus dans Pro | Edge | Oui |
Pour nos projets de développement CMS headless, nous utilisons généralement Cloudinary ou le pipeline d'image intégré du CMS (Sanity, Contentful, et Hygraph ont tous des API d'image correctes).
Option 3 : Cloudflare Polish + Next.js
Si vous êtes déjà derrière Cloudflare, leur fonction Polish peut gérer la conversion de format à la périphérie. Vous désactiverez l'optimisation d'image Next.js et laisserez Cloudflare faire le travail :
module.exports = {
images: {
unoptimized: true, // Laisser Cloudflare le gérer
},
};
Je n'aime pas vraiment cette approche car vous perdez le dimensionnement réactif que next/image fournit, mais cela fonctionne pour les configurations plus simples.
Mesurer ce qui compte : Outils et benchmarks
Vous ne pouvez pas améliorer ce que vous ne mesurez pas. Voici ma pile de test :
Outils de laboratoire
- Chrome DevTools Lighthouse (v12 depuis 2026) : Toujours le point de départ. Exécutez-le en mode incognito sans extensions.
- WebPageTest : Réglez-le sur Dulles, VA sur un Moto G Power avec 4G. Cela représente un vrai utilisateur « lent ».
- Unlighthouse : Analyse en masse votre site entier. Incroyable pour attraper les pages que vous avez oubliées.
Données de terrain
- Chrome UX Report (CrUX) : Les vraies données que Google utilise pour les signaux de classement. Disponible dans PageSpeed Insights et BigQuery.
- web-vitals.js : Ajoutez-le à votre application pour collecter les métriques d'utilisateurs réels :
// app/layout.tsx
import { onLCP, onINP, onCLS } from 'web-vitals';
if (typeof window !== 'undefined') {
onLCP(console.log);
onINP(console.log);
onCLS(console.log);
}
En production, envoyez-les à votre plateforme d'analytics au lieu de console.log. Nous utilisons une combinaison de Vercel Speed Insights et d'un endpoint personnalisé qui écrit vers BigQuery.
Objectifs de référence pour 2026
Basé sur les sites que nous avons auditées cette année, voici ce que « bon » signifie pour les sites Next.js riches en images :
- LCP sur mobile (p75) : < 1,8s (vous donne une marge sous le seuil de 2,0s)
- Poids total des images au-dessus du pli : < 200KB
- Temps de chargement de l'image héros : < 800ms sur 4G
- CLS des images : 0
Techniques avancées qui font vraiment la différence
Placeholders flous avec BlurHash
Next.js supporte nativement placeholder="blur" pour les imports statiques. Pour les images dynamiques (depuis un CMS), vous devrez générer des URL blur data :
import { getPlaiceholder } from 'plaiceholder';
export async function getStaticProps() {
const { base64 } = await getPlaiceholder('/path/to/image.jpg');
return {
props: { blurDataURL: base64 },
};
}
// Dans le composant
<Image
src={dynamicUrl}
alt="Dynamic image"
fill
placeholder="blur"
blurDataURL={blurDataURL}
/>
Cela n'améliore pas LCP directement, mais améliore dramatiquement les performances perçues et prévient CLS.
HTTP/3 et Early Hints
Si votre CDN supporte HTTP/3 (Cloudflare, Fastly, et Vercel le font tous), vous pouvez utiliser 103 Early Hints pour commencer à envoyer l'image LCP avant même que le document HTML soit complètement généré :
// middleware.ts
import { NextResponse } from 'next/server';
export function middleware(request) {
const response = NextResponse.next();
if (request.nextUrl.pathname === '/') {
response.headers.set(
'Link',
'</hero.avif>; rel=preload; as=image; type="image/avif"'
);
}
return response;
}
Skeleton Loading avec CSS `content-visibility`
Pour les longues pages avec de nombreuses images, content-visibility: auto indique au navigateur de sauter complètement le rendu du contenu hors écran :
.image-grid-item {
content-visibility: auto;
contain-intrinsic-size: 300px 200px; /* Taille estimée */
}
Cela a réduit INP de 30-40ms sur une page de liste de produits que nous avons optimisée le dernier trimestre.
Erreurs courantes que je vois à chaque audit
Utiliser
next/imagepour les SVG décoratifs : Utilisez simplement une balise<img>ou intégrez le SVG. Le pipeline d'optimisation ajoute une surcharge pour zéro bénéfice.Régler
unoptimizedglobalement parce que « les images semblent floues » : Fixez plutôt le paramètre de qualité.unoptimizedcontourne tout.Oublier le texte
alt: Ce n'est pas juste l'accessibilité -- la recherche d'images Google génère du trafic, et elle a besoin de texte alt pour indexer vos images.Ne pas régler
minimumCacheTTL: La valeur par défaut est 60 secondes. Cela signifie que votre serveur ré-optimise la même image chaque minute sous charge. Réglez-la à au moins2592000(30 jours).Utiliser des images source massives : Télécharger une photo DSLR 6000x4000px et s'attendre à ce que Next.js la gère. Pré-traitez vos images source à un maximum de 2x votre plus grande taille d'affichage.
Ignorer l'onglet Network : Ouvrez DevTools, filtrez par
Img, triez par taille. Vous trouverez des problèmes en 30 secondes.
Si vous avez du mal avec ces problèmes sur un site en production, c'est exactement le type de problème que nous résolvons. Consultez nos tarifs ou contactez-nous directement -- nous faisons des audits de performance comme engagements autonomes.
FAQ
next/image convertit-il automatiquement les images en AVIF ?
Oui, si vous avez 'image/avif' dans votre tableau images.formats dans next.config.js (il est inclus par défaut depuis Next.js 14). La conversion se fait à la demande lorsqu'un navigateur envoie un en-tête Accept qui inclut image/avif. La première requête est plus lente en raison de l'encodage, mais les requêtes ultérieures sont servies depuis le cache.
De combien AVIF réduit-il vraiment la taille des fichiers images par rapport à WebP ?
Dans nos tests sur des centaines d'images en production, AVIF est en moyenne 30-50% plus petit que WebP à qualité visuelle équivalente, et 50-70% plus petit que JPEG. Les gains sont les plus spectaculaires sur le contenu photographique. Pour les captures d'écran ou les images avec du texte, la différence se rétrécit à 15-25%.
Dois-je utiliser priority sur plusieurs images ?
Utilisez-le avec parcimonie -- seulement sur les images qui sont vraiment au-dessus du pli et visibles au chargement initial. Ajouter priority à plus de 2-3 images annule l'objectif car le navigateur ne peut pas tout prioriser simultanément. Pour votre héros de page d'accueil et peut-être un logo, c'est tout.
Pourquoi mon LCP est-il toujours lent même avec next/image et priority ?
La raison la plus courante est que votre temps de réponse serveur (TTFB) consomme votre budget. Si votre serveur Next.js prend 800ms pour répondre, il ne vous reste que 1,2 secondes pour que l'image se charge et s'affiche. Autres coupables : CSS qui bloque le rendu, gros bundles JavaScript qui retardent l'hydratation, ou l'image source sur un serveur d'origine lent.
Puis-je utiliser next/image avec des exports statiques (next export) ?
Pas avec l'optimisation intégrée. Les exports statiques nécessitent images.unoptimized: true ou un loader personnalisé pointant vers un service externe comme Cloudinary ou Imgix. C'est une raison pour laquelle nous recommandons parfois Astro pour les sites purement statiques -- sa gestion des images ne nécessite pas un serveur en cours d'exécution.
Comment gérer les images d'un CMS headless avec next/image ?
Ajoutez le domaine d'image du CMS à images.remotePatterns dans votre config. La plupart des plateformes CMS headless (Sanity, Contentful, Storyblok, Hygraph) ont leurs propres API de transformation d'image. Vous pouvez soit utiliser celles-ci via un loader personnalisé soit laisser Next.js gérer l'optimisation. Nous préférons généralement le pipeline natif du CMS pour les projets CMS headless car cela réduit la charge du serveur.
Quel est l'impact de l'optimisation des images sur les signaux de classement Core Web Vitals ?
Google a confirmé en 2025 que Core Web Vitals reste un signal de classement, bien que la pertinence du contenu domine toujours. Cela dit, pour les requêtes compétitives où la qualité du contenu est similaire dans les résultats principaux, CWV peut être le facteur décisif. Nous avons vu des sites se déplacer de 3-8 positions après avoir corrigé les problèmes LCP qui étaient principalement causés par des images non optimisées.
Dois-je lazy-charger toutes les images sous le pli ?
Oui, et Next.js le fait par défaut (sauf si vous ajoutez priority). L'attribut natif loading="lazy" est ce que next/image utilise en coulisse. Il n'y a pas besoin de bibliothèque de lazy loading basée sur JavaScript -- le lazy loading natif du navigateur est stable dans tous les navigateurs majeurs depuis 2022.