Skip to content

What Is Lazy Loading — Deferred Resource Loading Explained

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about What Is Lazy Loading. We cover key concepts, practical examples, and best practices to help you master this topic.

Lazy loading defers loading non-critical resources until needed, improving initial page load time, reducing bandwidth, and enhancing Core Web Vitals.

What You'll Learn

By the end of this tutorial, you'll understand what lazy loading is, why it matters for web performance, the different types of lazy loading (images, iframes, JS, CSS), and how to measure its impact.

Why It Matters

The average webpage is over 2MB, with images accounting for 50-70% of that weight. Loading everything upfront wastes bandwidth and slows initial render. Lazy loading defers what's not immediately visible, making pages load faster.

Real-World Use

A news article page has 20 images, but only the first 2 are visible above the fold. Lazy loading defers the remaining 18 images until the user scrolls. Initial page load drops from 3.2MB to 0.4MB, and Lighthouse performance improves by 40 points.

Lazy Loading Flow

graph TD
    A[Page Load] --> B[Load critical
above-fold content] A --> C[Defer non-critical
resources] B --> D[User sees
initial page] D --> E[User scrolls
or interacts] E --> F{Resource needed?} F -->|Yes| G[Load resource
on demand] F -->|No| H[Keep deferred] G --> I[Display content] H --> J[Save bandwidth] style B fill:#27ae60,color:#fff style C fill:#f39c12,color:#fff style G fill:#4a90d9,color:#fff style J fill:#27ae60,color:#fff

Native Lazy Loading

<!-- Native lazy loading — simplest approach -->
<img src="large-photo.jpg" alt="Gallery photo" loading="lazy" width="800" height="600">

<iframe src="widget.html" loading="lazy" width="400" height="300"></iframe>

<!-- Eager loading for critical images -->
<img src="hero.jpg" alt="Hero image" loading="eager" fetchpriority="high">

<!-- Browser support detection -->
<script>
    if ('loading' in HTMLImageElement.prototype) {
        console.log('Native lazy loading supported');
        document.querySelectorAll('img[loading="lazy"]').forEach(img => {
            img.src = img.dataset.src;
        });
    } else {
        console.log('Falling back to Intersection Observer');
        loadLazyImagesFallback();
    }
</script>

Measuring Impact

// Performance measurement before/after lazy loading
const perfComparison = {
    before: {
        pageWeight: '3.2 MB',
        imagesLoaded: 20,
        loadTime: '4.2s',
        lighthousePerformance: 45,
        lighthouseLCP: '3.1s'
    },
    after: {
        pageWeight: '0.4 MB (initial)',
        imagesLoaded: 2,
        loadTime: '1.1s',
        lighthousePerformance: 92,
        lighthouseLCP: '0.8s'
    },
    improvement: {
        weightReduction: '87.5%',
        loadTimeImprovement: '73.8%',
        performanceScore: '+47 points'
    }
};

// Test script for measuring lazy loading impact
async function measureLazyLoading() {
    const metrics = {
        totalImages: document.images.length,
        lazyImages: document.querySelectorAll('img[loading="lazy"]').length,
        eagerImages: document.querySelectorAll('img[loading="eager"]').length,
        totalSize: 0,
        loadedSize: 0
    };

    // Monitor network requests
    const observer = new PerformanceObserver((list) => {
        list.getEntries().forEach(entry => {
            if (entry.initiatorType === 'img') {
                metrics.totalSize += entry.transferSize || entry.encodedBodySize;
                if (entry.entryType === 'resource') {
                    metrics.loadedSize += entry.transferSize || entry.encodedBodySize;
                }
            }
        });
    });

    observer.observe({ entryTypes: ['resource'] });

    // Report metrics after page load
    window.addEventListener('load', () => {
        setTimeout(() => {
            console.log('Lazy Loading Metrics:', metrics);
            console.log(`Bandwidth saved: ${((1 - metrics.loadedSize / metrics.totalSize) * 100).toFixed(1)}%`);
        }, 3000);
    });
}

Common Mistakes

  1. Lazy loading above-the-fold images. The hero image and any image visible on initial load should load eagerly. Lazy loading them actually worsens LCP.
  2. Forgetting width and height attributes. Lazy loaded images without dimensions cause layout shifts. Always set width and height or use aspect-ratio CSS.
  3. Not providing a fallback for unsupported browsers. Older browsers don't support loading=lazy. Use Intersection Observer as a Polyfill.
  4. Lazy loading too aggressively. Everything deferred means nothing renders. Prioritize critical content (CSS, hero images, navigation).
  5. Not testing with slow connections. Lazy loading behaves differently on 3G vs WiFi. Test with throttled network conditions.

Practice Questions

  1. What problem does lazy loading solve for web performance?
  2. How does the native loading=lazy attribute work?
  3. What resources should NOT be lazy loaded?
  4. How do you measure the bandwidth savings from lazy loading?
  5. What happens when a browser doesn't support native lazy loading?

Challenge: Build a performance comparison page: load 20 images with and without lazy loading, measure page weight, load time, and Lighthouse scores for both versions, and present the results in a comparison table.

FAQ

Does lazy loading affect SEO?

Google's crawler renders JavaScript and loads lazy images. However, content hidden behind lazy loading that requires interaction may not be indexed. Use native loading=lazy which Google supports.

Can lazy loading be used for CSS and JavaScript?

Yes. CSS can be split into critical (above-fold) and non-critical (below-fold) styles. JavaScript can use dynamic imports and async/defer attributes.

What is the difference between lazy loading and async/defer?

Lazy loading loads resources when needed (usually on scroll). async/defer control when scripts execute during page load. They serve different purposes.

Does lazy loading work on all browsers?

Native loading=lazy works in Chrome, Firefox, Edge, and Safari 16.4+. For older browsers, use Intersection Observer as a fallback.

What is the ideal threshold for lazy loading?

Load images when they're 200-500px from entering the viewport. This ensures they're loaded before the user scrolls to them, preventing visible loading delays.

Mini Project

Build a photo gallery with performance tracking: create a gallery page with 30 images, lazy load images using native loading=lazy, implement an Intersection Observer fallback, display real-time bandwidth savings, and benchmark against a non-lazy-loaded version.

What's Next

You understand lazy loading fundamentals. Now learn about the Native loading Attribute in depth.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro