Intégration web angularforall.com

- Lazy loading images : attribut loading=lazy

Lazy Loading Loading=Lazy Performance Optimisation Web Vitals Images
Lazy loading images : attribut loading=lazy

Maîtrisez le lazy loading natif avec l'attribut loading. Optimisation performance, intersection observer, fallback. 11+ exemples et bonnes pratiques.

Pourquoi le lazy loading ?

Impact sur les performances :

  • LCP amélioré : Largest Contentful Paint = temps avant que le contenu principal soit visible
  • Moins de requêtes HTTP au chargement initial
  • Économie de bande passante pour les utilisateurs qui ne scrollent pas
  • Meilleure expérience mobile sur connexions 3G/4G lentes
Attention : Les images "lazy" doivent avoir des dimensions définies pour éviter les Cumulative Layout Shift (CLS). Le layout doit être stable.

L'attribut loading="lazy"

Utilisation basique

<!-- Image chargée avec lazy loading -->
<img
    src="image.jpg"
    alt="Description"
    loading="lazy"
    width="400"
    height="300"
/>

Attributs importants :

  • loading="lazy" : charge l'image quand elle approche du viewport
  • loading="eager" : charge immédiatement (par défaut)
  • width et height : obligatoires pour éviter le CLS

Quand utiliser lazy loading

<!-- Images au-dessus du fold : loading="eager" ou sans attribut -->
<img
    src="hero.jpg"
    alt="Hero image"
    loading="eager"
    width="800"
    height="400"
/>

<!-- Images au-dessous du fold : loading="lazy" -->
<img
    src="gallery-1.jpg"
    alt="Gallery image 1"
    loading="lazy"
    width="300"
    height="300"
/>

<!-- Images loin en bas : loading="lazy" -->
<img
    src="testimonial-image.jpg"
    alt="Testimonial"
    loading="lazy"
    width="200"
    height="200"
/>

Galerie d'images complète

<!-- Galerie avec lazy loading -->
<div class="gallery">
    <img src="image-1.jpg" alt="Image 1" loading="lazy" width="300" height="300" class="gallery-item">
    <img src="image-2.jpg" alt="Image 2" loading="lazy" width="300" height="300" class="gallery-item">
    <img src="image-3.jpg" alt="Image 3" loading="lazy" width="300" height="300" class="gallery-item">
    <img src="image-4.jpg" alt="Image 4" loading="lazy" width="300" height="300" class="gallery-item">
</div>

<style>
.gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1rem;
}
.gallery-item {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: cover;
}
</style>

Définir les dimensions (LCP et CLS)

Pourquoi les dimensions sont cruciales

Sans dimensions définies, le navigateur ne sait pas l'espace que l'image occupera. Cela cause des Cumulative Layout Shift (CLS) quand l'image charge.

<!-- ❌ Mauvais : pas de dimensions, CLS garanti -->
<img src="image.jpg" alt="Image" loading="lazy"/>

<!-- ✅ Bon : dimensions définies, pas de CLS -->
<img
    src="image.jpg"
    alt="Image"
    loading="lazy"
    width="400"
    height="300"
/>

Utiliser aspect-ratio pour le responsive

/* Garder le ratio 16:9 même si la largeur change */
img {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
}

/* Anciennes navigateurs sans aspect-ratio */
img {
    width: 100%;
    height: auto;
}

Placeholder technique : LQIP

<!-- Placeholder bas-res pendant le chargement -->
<img
    src="data:image/jpeg;base64,/9j/4AAQSkZJRg..."
    alt="Placeholder"
    loading="lazy"
    width="400"
    height="300"
    srcset="image-small.jpg 400w, image-medium.jpg 800w, image-large.jpg 1200w"
    style="background-size: cover;"
/>

Intersection Observer pour plus de contrôle

Lazy loading personnalisé

<img
    class="lazy"
    data-src="image.jpg"
    alt="Image"
    width="400"
    height="300"
    src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3C/svg%3E"
/>

JavaScript avec Intersection Observer

// Créer un Intersection Observer
const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
        if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src;

            // Écouter le chargement
            img.onload = () => {
                img.classList.add('loaded');
            };

            // Arrêter d'observer cet élément
            observer.unobserve(img);
        }
    });
}, {
    rootMargin: '50px' // Commencer à charger 50px avant d'entrer dans le viewport
});

// Observer toutes les images lazy
document.querySelectorAll('img.lazy').forEach(img => {
    imageObserver.observe(img);
});

Avec fade-in animation

img {
    transition: opacity 0.3s ease;
}

img.lazy {
    opacity: 0;
}

img.loaded {
    opacity: 1;
}

Lazy loading des iframes

loading="lazy" sur les iframes

<!-- Youtube, cartes, etc. avec lazy loading -->
<iframe
    src="https://www.youtube.com/embed/dQw4w9WgXcQ"
    width="560"
    height="315"
    title="Video"
    loading="lazy"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
></iframe>

<!-- Google Maps avec lazy loading -->
<iframe
    src="https://www.google.com/maps/embed?pb=..."
    width="400"
    height="300"
    loading="lazy"
></iframe>

Cela économise énormément de bande passante, surtout pour les pages avec plusieurs vidéos.

Lazy loading + images responsives

Combiner loading="lazy" et srcset

<img
    src="image-400w.jpg"
    srcset="image-400w.jpg 400w,
            image-800w.jpg 800w,
            image-1200w.jpg 1200w"
    sizes="(max-width: 600px) 100vw,
           (max-width: 1200px) 50vw,
           800px"
    alt="Responsive image"
    loading="lazy"
    width="800"
    height="600"
/>

Avec element picture

<picture>
    <source
        srcset="image-small.webp"
        media="(max-width: 600px)"
        type="image/webp"
    />
    <source
        srcset="image-large.webp"
        media="(min-width: 601px)"
        type="image/webp"
    />
    <img
        src="image-fallback.jpg"
        alt="Image"
        loading="lazy"
        width="800"
        height="600"
    />
</picture>

Fallback et polyfill

Détecter le support

// Vérifier si le navigateur supporte loading="lazy"
const supportsLazyLoading = 'loading' in HTMLImageElement.prototype;

if (!supportsLazyLoading) {
    // Charger un polyfill ou utiliser Intersection Observer
    loadPolyfill();
}

Polyfill avec Intersection Observer

// Pour les navigateurs n'ayant pas loading="lazy"
if (!('loading' in HTMLImageElement.prototype)) {
    const images = document.querySelectorAll('img[loading="lazy"]');

    const imageObserver = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const img = entry.target;
                img.src = img.src;
                imageObserver.unobserve(img);
            }
        });
    });

    images.forEach(img => imageObserver.observe(img));
}

Suivi et analytics

Tracker les images lazy loading

// Tracker quand une image lazy est chargée
document.querySelectorAll('img[loading="lazy"]').forEach(img => {
    img.addEventListener('load', () => {
        console.log(`Image chargée : ${img.alt}`);

        // Envoyer à Google Analytics, etc.
        if (window.gtag) {
            gtag('event', 'image_loaded', {
                'image_name': img.alt,
                'image_src': img.src
            });
        }
    });
});

Mesurer le LCP

// Mesurer le Largest Contentful Paint
const observer = new PerformanceObserver((entryList) => {
    const entries = entryList.getEntries();
    const lastEntry = entries[entries.length - 1];
    console.log('LCP :', lastEntry.renderTime || lastEntry.loadTime);
});

observer.observe({entryTypes: ['largest-contentful-paint']});

Conclusion

Lazy loading maîtrisé : Utilisez loading="lazy" pour les images non-critiques, et définissez toujours les dimensions pour éviter le CLS.

Checklist lazy loading :

  • ✅ Utiliser loading="lazy" sur images au-dessous du fold
  • ✅ Définir width et height (ou aspect-ratio)
  • ✅ Combiner avec srcset pour images responsives
  • ✅ Tester le CLS avec DevTools ou PageSpeed Insights
  • ✅ Implémenter fallback pour anciens navigateurs

Partager