Lazy loading, the practice of loading resources when needed and not before that, is often implemented on websites as faster loading times can be crucial for user experience or Google’s rating systems. Since July 2018 Google has increased the importance of page speed in its website grading systems, so faster loading websites have way better chance to appear on the first page of Google’s search results than slower loading ones.

Lazy Loading Resources

Images are the most common large files on websites, hence they are the main candidates to be lazy loaded. A very simple and popular way to achieve that is to create a JS function that populates the image src attribute once the user has scrolled to the image section.

<!-- This goes in the HTML file -->
<img class="lazy" src="placeholder-image.jpg" data-src="actual-image.jpg" alt="Image">

// This goes in the JS file
document.addEventListener("DOMContentLoaded", function() {
  let lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));
  let active = false;

  const lazyLoad = function() {
    if (active === false) {
      active = true;

      setTimeout(function() {
        lazyImages.forEach(function(lazyImage) {
          // Checking if the user has scrolled enough
          if ((lazyImage.getBoundingClientRect().top <= window.innerHeight && lazyImage.getBoundingClientRect().bottom >= 0) && getComputedStyle(lazyImage).display !== "none") {
            lazyImage.src = lazyImage.dataset.src;
            lazyImage.classList.remove("lazy");

            lazyImages = lazyImages.filter(function(image) {
              return image !== lazyImage;
            });

            // No need to use the event listeners if there are no images to be lazy loaded
            if (lazyImages.length === 0) {
              document.removeEventListener("scroll", lazyLoad);
              window.removeEventListener("resize", lazyLoad);
              window.removeEventListener("orientationchange", lazyLoad);
            }
          }
        });

        active = false;
      }, 250);
    }
  };

  document.addEventListener("scroll", lazyLoad);
  window.addEventListener("resize", lazyLoad);
  window.addEventListener("orientationchange", lazyLoad);
});

While the method above isn’t optimal in performance as it will be run every 250 milliseconds regardless if there’s anything to lazy load, it is often the preferred method because of its compatibility. Other popular implementations as the Intersection Observer may not run on IE or Edge.

The Intersection Observer itself works like that:

document.addEventListener("DOMContentLoaded", function() {
  var lazyImages = [].slice.call(document.querySelectorAll("img.lazy"));

  if ("IntersectionObserver" in window) {
    let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
      entries.forEach(function(entry) {
        if (entry.isIntersecting) {
          let lazyImage = entry.target;
          lazyImage.src = lazyImage.dataset.src;
          lazyImage.classList.remove("lazy");
          lazyImageObserver.unobserve(lazyImage);
        }
      });
    });
    lazyImages.forEach(function(lazyImage) {
      lazyImageObserver.observe(lazyImage);
    });
  } else {
    // If there is a problem with running the code above, consider using a more universal approach - like the first example
  }
});

Lazy loading videos is quite staightforward. For example:

<video controls preload="none" poster="video-placeholder.jpg">
  <source src="my-video.webm" type="video/webm">
  <source src="my-video.mp4" type="video/mp4">
</video>

We need to explicitly declare preload=”none” so no unnecessary video data is loaded before it’s needed.

Embedded Image Placeholders

HTML allows images to be declared using data URL scheme and Base64 encoding. In the HTML the image will look like this:

<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBD ... and so on for many more lines ... QAUUUUAf/Z"/>

Such Base64 encoding saves from HTTP requests and HTTP connections so it means faster loading of the website. A disadvantage of this method is that Base64 encoded images are larger than the original image and if an image is larger than several KBs, it does more harm than good and can even cause the image not to load at all.

Infinite Scroll

Lazy loading has greatly increased the usage of an interface solution called Infinite Scroll. It means that all the images and videos load on the same page on portions. Whenever the user scrolls enough, another portion of files is lazy loaded and appears on the page, respectively increasing the page height and usually making the page footer inaccessible. Infinite Scroll is used often on blogs and some popular blog platforms that offer it as a design are WordPress and Tumblr.

Risks when implementing Lazy Loading

  • Sometimes, improper indexing of the lazy loaded content can hurt the website performance in the search engine results.
  • If some content above the fold (at the top) of a webpage is being lazy loaded, it may create negative user experience since this content won’t be fully loaded until the DOM and the scripts are fully loaded too.

Was this post helpful?