Lazy Loading Images

Serhii Shramko /

Intersection Observer API allows us to load images only when they're about to enter the viewport. This optimization technique significantly improves initial page load performance, especially for image-heavy pages.

Implementation

interface LazyImageOptions {
  root?: Element | null;
  rootMargin?: string;
  threshold?: number | number[];
}

class LazyImageLoader {
  private observer: IntersectionObserver;

  constructor(options: LazyImageOptions = {}) {
    this.observer = new IntersectionObserver(this.handleIntersection, {
      root: options.root || null,
      rootMargin: options.rootMargin || '50px',
      threshold: options.threshold || 0
    });
  }

  private handleIntersection = (entries: IntersectionObserverEntry[]) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target as HTMLImageElement;
        const dataSrc = img.getAttribute('data-src');

        if (dataSrc) {
          img.src = dataSrc;
          img.removeAttribute('data-src');
          this.observer.unobserve(img);
        }
      }
    });
  };

  public observe(images: NodeListOf<HTMLImageElement> | HTMLImageElement[]) {
    images.forEach(img => this.observer.observe(img));
  }

  public disconnect() {
    this.observer.disconnect();
  }
}

Usage

<img class="lazy" data-src="path/to/image.jpg" src="https://placehold.co/600x600" width="600" height="600" alt="Lazy loaded image">
// Initialize
const lazyLoader = new LazyImageLoader({
  rootMargin: '50px', // Start loading 50px before the image enters viewport
});

const images = document.querySelectorAll<HTMLImageElement>('.lazy');

// Start observing
lazyLoader.observe(images);