Lazy loading is a technique that defers the loading of non-critical resources until they are actually needed, drastically improving initial page load times by prioritizing what the user sees first.

Let’s see it in action with a common scenario: images on a long webpage.

Consider this basic HTML for an image:

<img src="large-image.jpg" alt="A beautiful landscape">

When a browser encounters this, it immediately starts downloading large-image.jpg. If you have many such images, or images that are large in file size, this can significantly delay the time it takes for the user to see the rest of your page content.

Now, let’s introduce lazy loading using the loading="lazy" attribute, which is now a standard HTML feature:

<img src="large-image.jpg" alt="A beautiful landscape" loading="lazy">

With loading="lazy", the browser won’t download large-image.jpg until it determines that the image is likely to enter the viewport (the visible area of the screen) soon. This means the browser can focus on downloading critical content like HTML, CSS, and above-the-fold images first.

The Mechanics of Lazy Loading

The browser’s native lazy loading mechanism is remarkably simple. It uses a combination of the Intersection Observer API and heuristics. When an element with loading="lazy" is encountered, the browser doesn’t fetch its src or href immediately. Instead, it monitors the element’s position relative to the viewport. Once the element is a certain distance from entering the viewport (the exact threshold is determined by the browser and can vary), it triggers the loading of the resource.

This applies not only to images but also to iframes, which are often used for embedded content like videos or maps:

<iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen loading="lazy"></iframe>

The loading="lazy" attribute is the simplest and most effective way to implement lazy loading for these common elements. It’s supported by most modern browsers, including Chrome, Firefox, Safari, and Edge.

Why It Matters: The Impact on User Experience and SEO

The primary benefit of lazy loading is a snappier user experience. Users perceive pages as faster when they can see content quickly, even if some elements load later. This is crucial for engagement, as slow-loading pages often lead to higher bounce rates.

Search engines like Google also favor faster websites. Page speed is a ranking factor, and by reducing the initial load time, lazy loading can indirectly help improve your search engine rankings. Tools like Google PageSpeed Insights will often recommend lazy loading for images and iframes that are below the fold.

Beyond Native Lazy Loading: JavaScript Solutions

While native loading="lazy" is excellent, you might need more control or support for older browsers. This is where JavaScript-based solutions come in. These typically involve:

  1. Placeholder Elements: An initial, lightweight placeholder (e.g., a small, low-resolution image, a div with a background color, or a skeleton screen) is displayed.
  2. Intersection Observer: A JavaScript IntersectionObserver watches for when the placeholder element enters the viewport.
  3. Resource Loading: When the element is observed, the JavaScript swaps the placeholder’s source (e.g., data-src attribute) with the actual, full-resolution resource (src attribute) or loads the content for the iframe.

Here’s a simplified conceptual example of a JavaScript approach:

<img data-src="large-image.jpg" alt="A beautiful landscape" class="lazy-load">

And the corresponding JavaScript:

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = document.querySelectorAll("img.lazy-load");
  var observer = new IntersectionObserver(function(entries, observer) {
    entries.forEach(function(entry) {
      if (entry.isIntersecting) {
        var img = entry.target;
        img.src = img.dataset.src;
        img.classList.remove("lazy-load"); // Optional: remove class once loaded
        observer.unobserve(img);
      }
    });
  });

  lazyImages.forEach(function(img) {
    observer.observe(img);
  });
});

This JavaScript technique gives you fine-grained control over what gets loaded, when, and how. You can implement custom loading states, error handling, or even prioritize certain "lazy-loaded" assets over others.

The trick to effectively using JavaScript-based lazy loading is to ensure your placeholders are truly lightweight. A common pattern is to use a tiny, blurred version of the actual image as a data-src attribute, and then swap in the full image when the element becomes visible. This "blur-up" effect can make the perceived loading time feel even faster.

The next challenge is often optimizing the loading of other critical assets, such as JavaScript bundles or CSS files that are not immediately required for rendering.

Want structured learning?

Take the full Performance course →