Lazy Loading
The loading attribute provides native lazy loading for images and iframes without JavaScript libraries.
The Old Way
Section titled “The Old Way”<img data-src="image.jpg" class="lazy" alt="Lazy image">
<script>const lazyImages = document.querySelectorAll('.lazy');
const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.remove('lazy'); observer.unobserve(img); } });});
lazyImages.forEach(img => observer.observe(img));</script>Or with a library:
<script src="lazysizes.min.js"></script><img data-src="image.jpg" class="lazyload" alt="Image">Problems:
- Requires JavaScript to function
- Additional library adds weight
- Flash of empty space before load
- Must manage placeholder images
The Modern Way
Section titled “The Modern Way”<img src="image.jpg" alt="Description" loading="lazy">That’s it. The browser handles everything.
Benefits:
- Zero JavaScript required
- No external dependencies
- Browser optimizes load timing
- Works automatically with srcset
Loading Attribute Values
Section titled “Loading Attribute Values”| Value | Behavior |
|---|---|
lazy | Defer loading until near viewport |
eager | Load immediately (default behavior) |
Images
Section titled “Images”<!-- Lazy load offscreen images --><img src="photo.jpg" alt="Photo" loading="lazy">
<!-- Eager load above-the-fold images --><img src="hero.jpg" alt="Hero" loading="eager">
<!-- Works with srcset --><img src="photo-800.jpg" srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w" sizes="(max-width: 600px) 100vw, 50vw" alt="Photo" loading="lazy">Iframes
Section titled “Iframes”<!-- Lazy load embedded content --><iframe src="https://www.youtube.com/embed/VIDEO_ID" loading="lazy" title="Video title"></iframe>
<!-- Lazy load maps --><iframe src="https://maps.google.com/..." loading="lazy" title="Location map"></iframe>Best Practices
Section titled “Best Practices”Don’t Lazy Load Above-the-Fold Content
Section titled “Don’t Lazy Load Above-the-Fold Content”<!-- Hero image - load immediately --><img src="hero.jpg" alt="Hero" loading="eager" fetchpriority="high">
<!-- Below fold - lazy load --><img src="gallery-1.jpg" alt="Gallery" loading="lazy"><img src="gallery-2.jpg" alt="Gallery" loading="lazy">Combine with Dimensions
Section titled “Combine with Dimensions”Prevent layout shift by specifying dimensions:
<img src="photo.jpg" alt="Photo" loading="lazy" width="800" height="600">Or use CSS aspect-ratio:
img { aspect-ratio: 4 / 3; width: 100%; height: auto;}Combine with Decoding
Section titled “Combine with Decoding”<img src="photo.jpg" alt="Photo" loading="lazy" decoding="async">decoding="async"- Decode image off main threaddecoding="sync"- Decode immediately (default)decoding="auto"- Browser decides
Loading Threshold
Section titled “Loading Threshold”Browsers start loading lazy images before they enter the viewport. The exact distance varies by browser and connection speed. Typically:
- Fast connection: ~1250px before viewport
- Slow connection: ~2500px before viewport
You cannot customize this threshold with native lazy loading.
Feature Detection
Section titled “Feature Detection”if ('loading' in HTMLImageElement.prototype) { // Native lazy loading supported} else { // Fallback to Intersection Observer or library}Hybrid Approach
Section titled “Hybrid Approach”For browsers without support (rare now):
<img src="placeholder.jpg" data-src="actual.jpg" loading="lazy" class="lazy" alt="Description">
<script>if (!('loading' in HTMLImageElement.prototype)) { // Load lazysizes or use IntersectionObserver const script = document.createElement('script'); script.src = 'lazysizes.min.js'; document.body.appendChild(script);}</script>Browser Support
Section titled “Browser Support”Supported in all modern browsers. See caniuse.com/loading-lazy-attr.
Accessibility Considerations
Section titled “Accessibility Considerations”- Lazy loading doesn’t affect accessibility
- Screen readers announce images normally
- Alt text works the same way
- No ARIA attributes needed
Performance Tips
Section titled “Performance Tips”<!-- Optimal image loading --><img src="photo.jpg" alt="Description" loading="lazy" decoding="async" width="800" height="600">For critical above-fold images:
<img src="hero.jpg" alt="Hero" loading="eager" decoding="async" fetchpriority="high">When to Use
Section titled “When to Use”Use loading="lazy" for:
- Images below the fold
- Image galleries
- Long pages with many images
- Embedded iframes (videos, maps)
Use loading="eager" (or omit) for:
- Hero images
- Above-the-fold content
- Critical LCP (Largest Contentful Paint) images
- Small, critical icons
Consider JavaScript alternatives when:
- You need custom loading thresholds
- You want loading animations/placeholders
- Supporting very old browsers