Cours Next.js · Module 3: Styles et optimisation visuelle

Composant Image et optimisation des images dans Next.js 16

16 min de lecture
Dans cette leçon11

À Metropolis Quantum, la communication visuelle joue un rôle clé. Hologrammes futuristes, panneaux numériques et écrans immersifs sont omniprésents dans le paysage de la ville. Cependant, comme dans les vraies villes, les ingénieurs doivent garantir l'efficacité des systèmes d'affichage pour que les images se chargent rapidement et ne consomment pas trop de ressources.

Dans le monde des applications web, les images sont l'un des plus grands obstacles à l'obtention d'une performance optimale des pages. De grandes photos non compressées peuvent considérablement ralentir le chargement de la page et dégrader l'expérience utilisateur. Heureusement, Next.js 16 offre un outil puissant pour l'optimisation des images : le composant Image.

Pourquoi l'optimisation des images est-elle importante ?

Avant de plonger dans les détails du composant Image, il vaut la peine de comprendre pourquoi l'optimisation des images est si importante :

  1. La performance de la page - les images représentent souvent plus de 50 % du poids d'une page web
  2. Les Core Web Vitals - des métriques comme le LCP (Largest Contentful Paint) sont directement liées au temps de chargement des images
  3. Le SEO - les pages plus rapides sont mieux positionnées dans les résultats de recherche
  4. L'expérience utilisateur - personne n'aime attendre que le contenu se charge
  5. La consommation de données - pour les utilisateurs mobiles, de grandes images peuvent vite épuiser les forfaits de données
  6. L'accessibilité - des images correctement optimisées sont plus accessibles aux personnes ayant une connexion internet plus lente

L'approche traditionnelle des images en HTML

En HTML traditionnel, les images sont généralement ajoutées à l'aide de la balise <img> :

1<img src="/images/quantum-city.jpg" alt="Panorama Metropolis Quantum" />

Cette approche simple présente toutefois plusieurs inconvénients :

  1. Aucune optimisation automatique - les images sont servies dans leur format et leur taille d'origine
  2. Aucun responsive - les images ne s'adaptent pas automatiquement aux différentes tailles d'écran
  3. Aucun lazy loading - toutes les images sont chargées immédiatement, quelle que soit leur visibilité
  4. Aucune priorisation - il n'est pas facile de déterminer quelles images sont essentielles à l'affichage de la page

Le composant Image dans Next.js 16

Le composant Image de Next.js résout ces problèmes et offre un certain nombre d'avantages supplémentaires :

  1. L'optimisation automatique - la conversion vers des formats modernes (WebP, AVIF)
  2. L'ajustement de la taille - servir les images à la taille adaptée à l'appareil
  3. Le lazy loading - les images ne sont chargées que lorsqu'elles approchent du viewport
  4. L'évitement des décalages de mise en page - réserver l'espace des images avant leur chargement
  5. La prise en charge de plusieurs sources - une spécification facile d'images différentes pour différentes résolutions
  6. L'optimisation des Core Web Vitals - l'amélioration de métriques comme le LCP et le CLS

Utilisation de base du composant Image

Pour commencer à utiliser le composant Image, tu dois d'abord l'importer depuis next/image :

1import Image from 'next/image';
2
3export default function QuantumCityView() {
4  return (
5    <div className="city-view">
6      <h1>Panorama Metropolis Quantum</h1>
7      <Image
8        src="/images/quantum-city.jpg"
9        alt="Panorama Metropolis Quantum z lotu ptaka"
10        width={1200}
11        height={600}
12      />
13    </div>
14  );
15}

Dans l'exemple ci-dessus, le composant Image requiert plusieurs attributs :

  • src - le chemin de l'image
  • alt - le texte alternatif pour l'accessibilité
  • width et height - la largeur et la hauteur de l'image en pixels

Imports statiques d'images

Next.js permet aussi d'importer statiquement les images, ce qui offre des avantages supplémentaires comme la détection automatique des dimensions :

1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5  return (
6    <div className="city-view">
7      <h1>Panorama Metropolis Quantum</h1>
8      <Image
9        src={quantumCityImage}
10        alt="Panorama Metropolis Quantum z lotu ptaka"
11        // width and height are automatically determined from image metadata
12      />
13    </div>
14  );
15}

Images responsives

Le composant Image peut facilement s'adapter à différentes tailles d'écran à l'aide de styles CSS :

1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5  return (
6    <div className="city-view">
7      <h1>Panorama Metropolis Quantum</h1>
8      <div className="relative w-full h-[50vh]">
9        <Image
10          src={quantumCityImage}
11          alt="Panorama Metropolis Quantum z lotu ptaka"
12          fill
13          style={{ objectFit: 'cover' }}
14        />
15      </div>
16    </div>
17  );
18}

Dans cet exemple :

  • L'attribut fill fait remplir l'image dans le conteneur parent
  • Le style objectFit: 'cover' garantit que l'image conserve ses proportions, en la recadrant si nécessaire
  • Le conteneur parent doit avoir un positionnement relative ou absolute

Priorisation des images

Pour les images visibles « above the fold » (c'est-à-dire dans la partie supérieure de la page sans défilement), il vaut la peine d'utiliser l'attribut preload. Dans Next.js 16, il a remplacé l'attribut priority, déprécié, qui fonctionne encore mais ne doit plus être utilisé dans du nouveau code :

1<Image
2  src="/images/hero-quantum-city.jpg"
3  alt="Panorama Metropolis Quantum"
4  width={1200}
5  height={600}
6  preload
7/>

L'attribut preload provoque :

  • Next.js insère dans le <head> une balise <link rel="preload"> pour cette image
  • Le navigateur commence à télécharger l'image avant de l'atteindre dans le contenu de la page
  • L'image est disponible le plus tôt possible, ce qui améliore le LCP

La documentation de Next.js 16 conseille d'utiliser preload pour une seule image LCP, par exemple une photo hero. Dans les autres cas, loading="eager" ou fetchPriority="high" suffit.

Gérer les images provenant d'un CMS ou de sources externes

Pour utiliser des images provenant de sources externes (par ex. CMS, CDN, API), tu dois indiquer à Next.js les serveurs autorisés dans le fichier next.config.js. Les projets plus anciens le font avec l'option domains :

1// next.config.js
2module.exports = {
3  images: {
4    domains: ['cdn.quantum-city.com', 'images.cms-provider.com'],
5  },
6}

Cette option est dépréciée depuis Next.js 14 : dans Next.js 16, utilise plutôt « remotePatterns », qui offrent un contrôle plus précis :

1// next.config.js
2module.exports = {
3  images: {
4    remotePatterns: [
5      {
6        protocol: 'https',
7        hostname: 'cdn.quantum-city.com',
8        port: '',
9        pathname: '/images/**',
10      },
11      {
12        protocol: 'https',
13        hostname: '**.cms-provider.com',
14        port: '',
15        pathname: '/assets/**',
16      },
17    ],
18  },
19}

Placeholders et effet de flou

Next.js 16 offre plusieurs façons d'améliorer l'expérience utilisateur pendant le chargement des images :

Placeholder avec effet de flou

1<Image
2  src="/images/quantum-city.jpg"
3  alt="Panorama Metropolis Quantum"
4  width={1200}
5  height={600}
6  placeholder="blur"
7  blurDataURL="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1200' height='600'%3E%3Crect width='100%25' height='100%25' fill='%23071731'/%3E%3C/svg%3E"
8/>

Dans cet exemple :

  • placeholder="blur" active un effet de flou pendant le chargement de l'image
  • blurDataURL indique la couleur de fond utilisée pendant le chargement de l'image (encodée en URL base64)

Effet de flou automatique pour les imports statiques

Quand tu utilises un import statique d'image, Next.js génère automatiquement une version floutée :

1import Image from 'next/image';
2import quantumCityImage from '@/public/images/quantum-city.jpg';
3
4export default function QuantumCityView() {
5  return (
6    <Image
7      src={quantumCityImage}
8      alt="Panorama Metropolis Quantum"
9      placeholder="blur"
10      // blurDataURL jest generowany automatycznie
11    />
12  );
13}

Animations de chargement des images

Tu peux ajouter des animations de chargement des images à l'aide du CSS :

1import Image from 'next/image';
2import styles from './image.module.css';
3
4export default function QuantumCityView() {
5  return (
6    <Image
7      src="/images/quantum-city.jpg"
8      alt="Panorama Metropolis Quantum"
9      width={1200}
10      height={600}
11      className={styles.imageTransition}
12    />
13  );
14}
1/* image.module.css */
2.imageTransition {
3  opacity: 0;
4  transition: opacity 0.5s ease-in-out;
5}
6
7.imageTransition:global(.loaded) {
8  opacity: 1;
9}

Fonctionnalités avancées du composant Image

Images adaptatives et art direction

Si tu veux afficher des images différentes selon la taille d'écran, tu peux utiliser l'attribut srcSet :

1<div className="relative aspect-video w-full">
2  <picture>
3    <source
4      media="(max-width: 640px)"
5      srcSet="/images/quantum-city-mobile.jpg"
6    />
7    <source
8      media="(max-width: 1024px)"
9      srcSet="/images/quantum-city-tablet.jpg"
10    />
11    <source
12      media="(min-width: 1025px)"
13      srcSet="/images/quantum-city-desktop.jpg"
14    />
15    <Image
16      src="/images/quantum-city-desktop.jpg"
17      alt="Panorama Metropolis Quantum"
18      fill
19      style={{ objectFit: 'cover' }}
20    />
21  </picture>
22</div>

Gérer les images dans différents formats

Bien que Next.js convertisse automatiquement les images en WebP, tu peux aussi utiliser la balise <picture> pour gérer différents formats :

1<picture>
2  <source srcSet="/images/quantum-city.avif" type="image/avif" />
3  <source srcSet="/images/quantum-city.webp" type="image/webp" />
4  <Image
5    src="/images/quantum-city.jpg"
6    alt="Panorama Metropolis Quantum"
7    width={1200}
8    height={600}
9  />
10</picture>

Gérer les images avec transparence

Pour les images avec transparence (PNG, SVG), il vaut la peine d'envisager de désactiver la conversion WebP :

1<Image
2  src="/images/quantum-logo.png"
3  alt="Logo Metropolis Quantum"
4  width={200}
5  height={200}
6  style={{ objectFit: 'contain' }}
7  unoptimized
8/>

L'attribut unoptimized désactive l'optimisation de Next.js pour l'image concernée, ce qui peut être utile pour :

  • Les images avec transparence
  • Les images déjà optimisées
  • Les GIF animés

Configurer l'optimisation des images dans Next.js 16

Next.js offre de nombreuses options de configuration pour l'optimisation des images dans le fichier next.config.js :

1// next.config.js
2module.exports = {
3  images: {
4    // Deprecated since Next.js 14 - use remotePatterns instead of domains
5    domains: ['cdn.quantum-city.com'],
6
7    // More detailed configuration for external images
8    remotePatterns: [
9      {
10        protocol: 'https',
11        hostname: '**.cms-provider.com',
12        port: '',
13        pathname: '/assets/**',
14      },
15    ],
16
17    // Supported formats
18    formats: ['image/webp', 'image/avif'],
19
20    // Valeurs de quality autorisées (depuis Next.js 16, seulement [75] par défaut)
21    qualities: [50, 75, 90],
22
23    // Configuration du cache (depuis Next.js 16, 14400 s par défaut, soit 4 heures)
24    minimumCacheTTL: 60, // en secondes
25
26    // Image size limits
27    deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
28    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // depuis Next.js 16, 16 ne figure plus dans la liste par défaut
29
30    // Custom image loader (e.g., Cloudinary, imgix)
31    loader: 'default',
32
33    // Path to image optimization endpoint
34    path: '/_next/image',
35
36    // Disabling automatic optimization for all images
37    unoptimized: false,
38  },
39}

Next.js 16 a modifié plusieurs valeurs par défaut : minimumCacheTTL vaut désormais 4 heures (60 secondes auparavant), la largeur de 16 pixels a disparu de imageSizes, et qualities n'autorise par défaut que la qualité 75. De nouvelles options de sécurité sont aussi apparues : maximumRedirects (au plus 3 redirections par défaut) et dangerouslyAllowLocalIP, sans laquelle Next.js n'optimise pas les images provenant d'adresses locales.

Utiliser les loaders de fournisseurs externes

Next.js prend aussi en charge les services d'optimisation d'images populaires :

1// next.config.js
2module.exports = {
3  images: {
4    loader: 'cloudinary',
5    loaderFile: './my/image/loader.js',
6    // Domena Cloudinary
7    domains: ['res.cloudinary.com'],
8  },
9}

Tu peux aussi créer ton propre loader :

1// my/image/loader.js
2export default function myImageLoader({ src, width, quality }) {
3  return `https://cdn.quantum-city.com/images/${src}?w=${width}&q=${quality || 75}`
4}

Et l'utiliser dans le composant Image :

1import Image from 'next/image';
2import myLoader from '@/my/image/loader';
3
4export default function QuantumCityView() {
5  return (
6    <Image
7      loader={myLoader}
8      src="quantum-city.jpg"
9      alt="Panorama Metropolis Quantum"
10      width={1200}
11      height={600}
12    />
13  );
14}

Exemples d'application pratiques

1. Galerie d'images avec lazy loading

1// components/quantum-gallery.tsx
2import { useState } from 'react';
3import Image from 'next/image';
4
5const images = [
6  { src: '/images/quantum-city-1.jpg', alt: 'Panorama Metropolis Quantum' },
7  { src: '/images/quantum-city-2.jpg', alt: 'Dzielnica Business Quantum' },
8  { src: '/images/quantum-city-3.jpg', alt: 'Parki Kwantowe' },
9  { src: '/images/quantum-city-4.jpg', alt: 'Architecture Quantique' },
10  { src: '/images/quantum-city-5.jpg', alt: 'Transport Kwantowy' },
11  // more images...
12];
13
14export default function QuantumGallery() {
15  const [selectedImage, setSelectedImage] = useState(null);
16
17  return (
18    <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
19      <h2 className="text-3xl font-bold mb-6">Galerie Metropolis Quantum</h2>
20
21      {/* Display selected image */}
22      {selectedImage && (
23        <div className="fixed inset-0 bg-black/75 flex items-center justify-center z-50">
24          <div className="max-w-4xl mx-auto p-4">
25            <div className="relative w-full" style={{ height: '80vh' }}>
26              <Image
27                src={selectedImage.src}
28                alt={selectedImage.alt}
29                fill
30                style={{ objectFit: 'contain' }}
31                preload
32              />
33            </div>
34            <button
35              className="absolute top-4 right-4 text-white text-2xl"
36              onClick={() => setSelectedImage(null)}
37            >
38              &times;
39            </button>
40          </div>
41        </div>
42      )}
43
44      {/* Image grid */}
45      <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
46        {images.map((image, index) => (
47          <div
48            key={index}
49            className="relative aspect-square overflow-hidden rounded-lg cursor-pointer hover:opacity-90 transition-opacity"
50            onClick={() => setSelectedImage(image)}
51          >
52            <Image
53              src={image.src}
54              alt={image.alt}
55              fill
56              style={{ objectFit: 'cover' }}
57              sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, (max-width: 1024px) 33vw, 25vw"
58              // First image is priority, rest are loaded lazily
59              preload={index === 0}
60            />
61          </div>
62        ))}
63      </div>
64    </div>
65  );
66}

2. Bannière responsive avec des images différentes selon les appareils

1// components/quantum-hero.tsx
2import Image from 'next/image';
3
4export default function QuantumHero() {
5  return (
6    <div className="relative">
7      {/* Image for mobile devices */}
8      <div className="sm:hidden relative h-[50vh]">
9        <Image
10          src="/images/quantum-hero-mobile.jpg"
11          alt="Metropolis Quantum - City of the Future"
12          fill
13          style={{ objectFit: 'cover' }}
14          preload
15        />
16      </div>
17
18      {/* Image for tablets */}
19      <div className="hidden sm:block md:hidden relative h-[60vh]">
20        <Image
21          src="/images/quantum-hero-tablet.jpg"
22          alt="Metropolis Quantum - City of the Future"
23          fill
24          style={{ objectFit: 'cover' }}
25          preload
26        />
27      </div>
28
29      {/* Image for desktops */}
30      <div className="hidden md:block relative h-[70vh]">
31        <Image
32          src="/images/quantum-hero-desktop.jpg"
33          alt="Metropolis Quantum - City of the Future"
34          fill
35          style={{ objectFit: 'cover' }}
36          preload
37        />
38      </div>
39
40      {/* Overlay content */}
41      <div className="absolute inset-0 flex items-center justify-center">
42        <div className="text-center text-white p-4 backdrop-blur-sm bg-black/30 rounded-lg max-w-2xl">
43          <h1 className="text-4xl sm:text-5xl md:text-6xl font-bold mb-4">
44            Metropolis Quantum
45          </h1>
46          <p className="text-xl sm:text-2xl md:text-3xl">
47            The city of the future awaits you
48          </p>
49        </div>
50      </div>
51    </div>
52  );
53}

3. Cards produit avec images

1// components/quantum-product-card.tsx
2import Image from 'next/image';
3import { useState } from 'react';
4
5interface ProductCardProps {
6  product: {
7    id: string;
8    name: string;
9    image: string;
10    price: number;
11    description: string;
12  };
13}
14
15export default function ProductCard({ product }: ProductCardProps) {
16  const [isLoading, setIsLoading] = useState(true);
17
18  return (
19    <div className="bg-white dark:bg-gray-800 rounded-lg shadow-lg overflow-hidden">
20      <div className="relative h-64 w-full bg-gray-200 dark:bg-gray-700">
21        <Image
22          src={product.image}
23          alt={product.name}
24          fill
25          style={{ objectFit: 'cover' }}
26          sizes="(max-width: 768px) 100vw, 33vw"
27          className={`
28            duration-700 ease-in-out
29            ${isLoading ? 'scale-110 blur-xl grayscale' : 'scale-100 blur-0 grayscale-0'}
30          `}
31          onLoad={() => setIsLoading(false)}
32        />
33      </div>
34      <div className="p-4">
35        <h3 className="text-xl font-semibold mb-2 dark:text-white">{product.name}</h3>
36        <p className="text-gray-600 dark:text-gray-300 mb-2">{product.description}</p>
37        <div className="flex justify-between items-center">
38          <span className="text-lg font-bold dark:text-white">
39            {new Intl.NumberFormat('pl-PL', { style: 'currency', currency: 'PLN' }).format(product.price)}
40          </span>
41          <button className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-md">
42            Ajouter au panier
43          </button>
44        </div>
45      </div>
46    </div>
47  );
48}

Bonnes pratiques de travail avec le composant Image

  1. Spécifie toujours les dimensions - pour les images avec l'attribut src, définis toujours width et height ou utilise fill avec un conteneur aux dimensions définies
  2. Utilise l'attribut sizes - aide à fournir des tailles d'image adaptées aux différents appareils
  3. Priorise les images « above the fold » - utilise preload (anciennement priority) pour l'image la plus importante visible sans défilement
  4. Utilise des formats appropriés - laisse Next.js convertir automatiquement en WebP/AVIF
  5. Optimise pour les Core Web Vitals - maintiens un LCP et un CLS faibles
  6. Utilise des imports statiques pour les images locales
  7. N'abuse pas de unoptimized - ne l'utilise que dans les cas justifiés
  8. Utilise des valeurs alt parlantes - pour l'accessibilité et le SEO
  9. Prends en charge différents formats - configure le support d'AVIF et de WebP dans next.config.js

Prise en charge des formats d'image dans Next.js 16

Next.js prend en charge la conversion automatique des images vers des formats modernes. Par défaut, Next.js utilise le format WebP, qui offre une bonne compression tout en conservant la qualité. Tu peux toutefois aussi configurer la prise en charge du format AVIF, qui offre une compression encore meilleure :

1// next.config.js
2module.exports = {
3  images: {
4    formats: ['image/avif', 'image/webp'],
5  },
6}

Comparaison des formats d'image

FormatAvantagesInconvénientsPrise en charge navigateur
JPEGLargement pris en charge, bon pour la photographiePas de transparence, plus volumineux que les formats récentsTous les navigateurs
PNGPrend en charge la transparence, sans perteFichier volumineuxTous les navigateurs
WebPPlus léger que JPEG/PNG, prend en charge la transparencePrise en charge incomplète sur les anciens navigateurs~95 % des navigateurs
AVIFMeilleure compression, bonne qualitéPrise en charge limitée, encodage plus lent~70 % des navigateurs

Débogage et résolution de problèmes

Problème : les images sont floues ou de mauvaise qualité

Solution : ajuste le paramètre quality :

1<Image
2  src="/images/quantum-city.jpg"
3  alt="Panorama Metropolis Quantum"
4  width={1200}
5  height={600}
6  quality={90} // 75 par défaut
7/>

Dans Next.js 16, la valeur de quality doit figurer dans la liste images.qualities de next.config. Par défaut, la liste ne contient que 75 : si tu n'ajoutes pas 90, Next.js utilise la valeur autorisée la plus proche, c'est-à-dire 75 :

1// next.config.js
2module.exports = {
3  images: {
4    qualities: [50, 75, 90],
5  },
6};

L'image est maintenant générée en qualité 90, tandis que les autres images peuvent continuer à utiliser la valeur par défaut de 75.

Problème : décalage de mise en page pendant le chargement de l'image

Solution : spécifie toujours les dimensions de l'image ou utilise fill avec un conteneur aux dimensions définies :

1<div className="relative w-full aspect-video">
2  <Image
3    src="/images/quantum-city.jpg"
4    alt="Panorama Metropolis Quantum"
5    fill
6    style={{ objectFit: 'cover' }}
7  />
8</div>

Problème : les images ne sont pas responsives sur différents appareils

Solution : utilise l'attribut sizes :

1<Image
2  src="/images/quantum-city.jpg"
3  alt="Panorama Metropolis Quantum"
4  width={1200}
5  height={600}
6  sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
7/>

Problème : les images SVG ne s'affichent pas correctement

Solution : pour les fichiers SVG, la meilleure option est souvent d'utiliser unoptimized :

1<Image
2  src="/images/logo.svg"
3  alt="Logo Metropolis Quantum"
4  width={200}
5  height={200}
6  unoptimized
7/>

Optimisation des images au-delà du composant Image

En plus du composant Image, il vaut aussi la peine d'utiliser d'autres techniques d'optimisation des images :

1. Optimiser les images avant de les ajouter au projet

Avant d'ajouter des images au projet, il vaut la peine de les optimiser à l'aide d'outils comme :

  • ImageOptim
  • Squoosh
  • TinyPNG
  • SVGO (for SVG files)

2. Utiliser un CDN pour servir les images

L'utilisation d'un CDN (Content Delivery Network) peut considérablement accélérer la livraison des images :

1// next.config.js
2module.exports = {
3  images: {
4    loader: 'akamai',
5    path: 'https://cdn.quantum-city.com',
6  },
7}

3. Utiliser la technique de l'« art direction » pour différents appareils

1<picture>
2  <source media="(max-width: 640px)" srcSet="/images/banner-mobile.jpg" />
3  <source media="(max-width: 1024px)" srcSet="/images/banner-tablet.jpg" />
4  <source media="(min-width: 1025px)" srcSet="/images/banner-desktop.jpg" />
5  <img src="/images/banner-fallback.jpg" alt="Banner" />
6</picture>

4. Utiliser la technique des « responsive images » avec srcset

1<img
2  src="/images/quantum-city.jpg"
3  srcSet="
4    /images/quantum-city-small.jpg 640w,
5    /images/quantum-city-medium.jpg 1024w,
6    /images/quantum-city-large.jpg 1920w
7  "
8  sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw"
9  alt="Panorama Metropolis Quantum"
10/>

Résumé

L'optimisation des images est un aspect crucial de la création d'applications web performantes. Next.js 16 offre un composant Image puissant qui gère automatiquement de nombreux aspects de l'optimisation :

  1. L'optimisation automatique - la conversion vers des formats modernes (WebP, AVIF)
  2. L'ajustement de la taille - servir les images à la taille adaptée à l'appareil
  3. Le lazy loading - les images ne sont chargées que lorsqu'elles approchent du viewport
  4. L'évitement des décalages de mise en page - réserver l'espace des images avant leur chargement
  5. La prise en charge de plusieurs sources - une spécification facile d'images différentes pour différentes résolutions

Grâce à ces fonctionnalités, tu peux créer des applications qui se chargent plus vite, consomment moins de données et offrent une meilleure expérience utilisateur. Tout comme les ingénieurs de Metropolis Quantum optimisent les systèmes d'affichage holographiques et les panneaux numériques, tu peux optimiser les images de ton application Next.js pour offrir aux utilisateurs une expérience fluide et performante.

Dans le prochain chapitre, nous découvrirons différentes stratégies de chargement des images (lazy, eager, priority), ce qui nous permettra d'adapter encore davantage le comportement des images aux besoins de ton application.

Code de cette leçon : app/page.tsx
1// Next.js Image Component - Optimization Demo
2'use client';
3
4import { useState } from 'react';
5
6// Note: In a real Next.js project, you'd use:
7// import Image from 'next/image';
8// Here we demonstrate the concepts with standard img tags
9
10export default function ImageOptimizationDemo() {
11  const [showComparison, setShowComparison] = useState(false);
12
13  return (
14    <div className="min-h-screen bg-gray-900 text-white p-8">
15      <div className="max-w-4xl mx-auto">
16        <h1 className="text-3xl font-bold mb-2">Image Optimization in Next.js 16</h1>
17        <p className="text-gray-400 mb-8">
18          Automatic optimization, lazy loading, and responsive images
19        </p>
20
21        {/* Traditional vs Next.js Image comparison */}
22        <section className="mb-12">
23          <h2 className="text-xl font-semibold mb-4">Traditional HTML vs Next.js Image</h2>
24
25          <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
26            {/* Traditional approach */}
27            <div className="bg-gray-800 rounded-lg p-6">
28              <h3 className="text-red-400 font-mono mb-3">Traditional {"<img>"}</h3>
29              <pre className="bg-gray-900 p-4 rounded text-sm overflow-x-auto">
30{`<img
31  src="/photo.jpg"
32  alt="City panorama"
33  width="800"
34  height="600"
35/>`}
36              </pre>
37              <ul className="mt-4 space-y-2 text-sm text-gray-400">
38                <li>• No automatic optimization</li>
39                <li>• No lazy loading by default</li>
40                <li>• No responsive sizing</li>
41                <li>• Can cause layout shift (CLS)</li>
42              </ul>
43            </div>
44
45            {/* Next.js Image approach */}
46            <div className="bg-gray-800 rounded-lg p-6">
47              <h3 className="text-green-400 font-mono mb-3">Next.js {"<Image>"}</h3>
48              <pre className="bg-gray-900 p-4 rounded text-sm overflow-x-auto">
49{`import Image from 'next/image';
50
51<Image
52  src="/photo.jpg"
53  alt="City panorama"
54  width={800}
55  height={600}
56  placeholder="blur"
57/>`}
58              </pre>
59              <ul className="mt-4 space-y-2 text-sm text-gray-400">
60                <li>Auto WebP/AVIF conversion</li>
61                <li>Built-in lazy loading</li>
62                <li>Responsive srcset</li>
63                <li>Prevents layout shift</li>
64              </ul>
65            </div>
66          </div>
67        </section>
68
69        {/* Image properties demo */}
70        <section className="mb-12">
71          <h2 className="text-xl font-semibold mb-4">Key Properties</h2>
72          <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
73            <div className="bg-gray-800 rounded-lg p-4">
74              <h3 className="text-blue-400 font-semibold mb-2">fill</h3>
75              <p className="text-sm text-gray-400">
76                Image fills parent container. Use with position: relative on parent.
77              </p>
78              <code className="text-xs text-green-400 mt-2 block">
79                {"<Image fill style={{objectFit: 'cover'}} />"}
80              </code>
81            </div>
82            <div className="bg-gray-800 rounded-lg p-4">
83              <h3 className="text-purple-400 font-semibold mb-2">sizes</h3>
84              <p className="text-sm text-gray-400">
85                Responsive breakpoints for different viewport widths.
86              </p>
87              <code className="text-xs text-green-400 mt-2 block">
88                {'sizes="(max-width: 768px) 100vw, 50vw"'}
89              </code>
90            </div>
91            <div className="bg-gray-800 rounded-lg p-4">
92              <h3 className="text-yellow-400 font-semibold mb-2">placeholder</h3>
93              <p className="text-sm text-gray-400">
94                Show blur or empty placeholder while image loads.
95              </p>
96              <code className="text-xs text-green-400 mt-2 block">
97                {'placeholder="blur" blurDataURL="..."'}
98              </code>
99            </div>
100          </div>
101        </section>
102      </div>
103    </div>
104  );
105}

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. En Tailwind CSS, la classe 'flex justify-center items-center' signifie :

  2. 2. Le CSS-in-JS permet :

Tâches pratiques dans le jeu

  • Éditeur de code

    Crée du CSS avec des media queries pour un design responsive mobile-first (breakpoints sm, md, lg, xl)

  • Tri horizontal

    Place les éléments dans le bon ordre : return { → notFound: → true

  • Clique dans l'ordre

    Reconstitue la syntaxe d'une media query avec min-width

  • Éditeur de code

    Crée une mise en page avec header, sidebar, contenu principal et footer en utilisant CSS Grid

Articles utiles