Intersection Observer API – Lazy loading

Posted by

Intersection observer API can observe whether the elements are located within or at the intersection of the viewport. It observes changes constantly without needing to register events. In other words, it provides an alternative solution for exhaustive watch processes that used to be done by scroll events. The use of intersection observer API can replace the potential expensive scroll event processes of lazy loading.

In order to implement lazy loading with the intersection observer, the article will go through the steps below.

  1. Create an intersection observer
  2. Target an element to be observed
  3. Register an callback to be executed
  4. Check browser support
  5. Lazy loading – code example

Create an intersection observer

IntersectionObserver takes a callback function and options. Once the target elements are observed in the viewport, the callback function will run.

var options = {
    rootMargin: "100px 0px"
}
var observer = new IntersectionObserver(callback, options);

Specify the margin around the viewport with rootMargin, which expands its intersection border. In other words, you can load images before they are actually visible on the screen.

Target an element to be observed

Register the target elements to observe. observer.observe(element) to start the watch process.

observer.observe(element);

Register an callback to be executed

The callback function has access to two kinds of objects: entries and observer. Each entry offers the information about the target element. entry.isIntersecting can tell you whether the element is at the intersection of the viewport or not. observer is the intersection observer object itself, which offers methods such as observe and unobserve.

function callback(entries, observer) {
       entries.forEach(function(entry) {
            if(!entry.isIntersecting) {
                return ;
            }
            // do something
            observer.unobserve(element);
        });
}

Check browser support

Intersection Observer API is not supported by IE and Safari on iOS older than 12.2. It is important to check support before running the code and to provide a fallback process for those browsers. Also, make sure to check the methods used as well because not every browser offers its full support. Please check MDN for more information.

function isSupported() {
    /* check the availability of Intersection Observer and its methods */
    if (!('IntersectionObserver' in window) ||
        !('IntersectionObserverEntry' in window) ||
        !('isIntersecting' in window.IntersectionObserverEntry.prototype)
    ) {
        return false;
    }
    return true;
}

Lazy Loading – code example

The code below is an example of lazy loading with the intersection observer. In your HTML, set img.data-src to the url of an image and img.src to the default image. The default image should be a light file such as a gif file or base64 string. The code below will set img.src to img.data-src value if the target image tags come across at the intersection of the viewport.

registerIoLazyLoading();
function registerIoLazyLoading() {
    var images = document.querySelectorAll("img[data-src]");
    var lazyPathProp = 'data-src';
    var options = {
        rootMargin: "100px 0px"
    }

    /* check browser support */
    if(!isSupported()) {
        Array.prototype.forEach.call(images, function(img) {
            load(img);
        });
        return ;
    }

    /* lazy load images once it gets as close as 100px or less to the viewport */
    var observer = new IntersectionObserver(lazyload, options);
    Array.prototype.forEach.call(images, function(img) {
        observer.observe(img);
    });

    function lazyload(entries, observer) {
        entries.forEach(function(entry) {
            if(!entry.isIntersecting) {
                return ;
            }
            var img = entry.target;
            load(img);
            observer.unobserve(img);
        });
    }

    function load(img) {
        var imagePath = img.getAttribute(lazyPathProp);
        if (imagePath) {
            img.src = imagePath;
        }
    }

    function isSupported() {
        /* check the availability of Intersection Observer and its methods */
        if (!('IntersectionObserver' in window) ||
            !('IntersectionObserverEntry' in window) ||
            !('isIntersecting' in window.IntersectionObserverEntry.prototype)
        ) {
            return false;
        }
        return true;
    }
}

Thanks for reading.

Hope you enjoyed the article. If you have any question or opinion to share, feel free to write some comments.

Facebook Comments