Intersection Observer for Fun and Lazyloading

Nobody talks about it but something cool has been going on as browsers implement new features. Features that used to take massive jquery libraries like datepickers or client-side validation are now builtin to HTML. Layouts that used to be impossible, or otherwise were the sort of thing I wanted to try just for the challenge, are trivial in CSS grid.

One library I’ve been using for almost 4 years is lazysizes.js. If you’re a front end developer you’re likely familiar.

Minified, lazysizes is 6.62kb. It’s not much but it’s not nothing.

The following doesn’t do quite everything lazysizes does. I don’t cover all the features of the picture element. But it does everything I need on this site in 396 bytes when minified. Not bad.

// 
// LazyLoad images and iframes.
// Backwards compatible with lazysizes.js
// 
function bindLazyLoad() {
  const lazyLoadObserver = new IntersectionObserver((entries, observer) => {

    // Grab the elements that are actually in view
    const elements = entries.filter((entry) => entry.isIntersecting)
                      .map((entry) => entry.target);

    elements.forEach((el) => {
      // data-src -> src
      // lazyload -> lazyloaded
      const src = el.getAttribute('data-src');

      if (src) {
        el.removeAttribute('data-src');
        el.setAttribute('src', src);
        el.classList.add('lazyloaded');
        el.classList.remove('lazyload');          
      }

      // And now forget about this so we don't
      // try to load it again
      observer.unobserve(el);
    });
  }, {
    rootMargin: '500px'
  });

  // Observe all the lazyload elements
  [...document.querySelectorAll('.lazyload')].map((el) => {
    lazyLoadObserver.observe(el);
  });
}

That said, you probably shouldn’t abandon the old way in production.

Safari and IE11 don’t support IntersectionObserver . While I don’t care about IE11 on this site, iOS is a problem.

The Polyfill doesn’t look terrible, but since it users scroll handlers without LazySizes builtin throttling, and it’s 7kb, it wipes out any performance benefits we were aiming for.

For now I’ve implemented the above code and conditionally load the polyfill through Polyfill.io.

Does this matter or have any affect on the user experience at all? No. But this is a toy site, and half the reason I have it is to try out new techniques like this.