Implementing Efficient Image Loading in JavaScript

Loading Images When They Enter the Viewport

HTML Structure

<img data-src="image-url-here" class="lazy">

JavaScript Implementation

const lazyLoad = () => {
    const images = document.querySelectorAll('img.lazy');
    
    images.forEach(image => {
        const rect = image.getBoundingClientRect();
        const isVisible = rect.top < window.innerHeight;
        const hasNoSource = !image.src;
        
        if (isVisible && hasNoSource) {
            image.src = image.dataset.src;
        }
    });
};

The getBoundingClientRect method returns a DOMRect object containing the size and position of an element relative to the viewport. This method provides read-only properties including left, top, right, bottom, x, y, width, and height, all measured in pixels. Properties like top and left are calculated relative to the viewport's top-left corner.

Since this method accounts for scrolling within the viewport, the top and left values change immediately when the user scrolls. These values are relative to the viewport, not the entire document. To calculate positions relative to the document's top-left corner, add the current scroll offsets (window.scrollX and window.scrollY) to the top and left values.

Using IntersectionObserver API

const setupObserver = () => {
    const images = document.querySelectorAll('img[data-src]');
    
    const observer = new IntersectionObserver(entries => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const image = entry.target;
                image.src = image.dataset.src;
                observer.unobserve(image);
            }
        });
    });
    
    images.forEach(image => observer.observe(image));
};

Reference: MDN IntersectionObserver Documentation

Loading Thumbnails Before High-Resolution Images

HTML Structure

<img id="preview" src="thumbnail-url">

JavaScript Implementation

const loadFullImage = (highResUrl, onComplete) => {
    const preview = document.getElementById('preview');
    
    if (!preview || !highResUrl) return;
    
    const highResImage = new Image();
    highResImage.src = highResUrl;
    
    highResImage.onload = () => {
        preview.src = highResImage.src;
        if (typeof onComplete === 'function') {
            onComplete();
        }
    };
};

This approach first displays a smaller thumbnail image, then loads the high-resoluiton version in the background. Once the full-resolution image finishes loading, it replaces the thumbnail src. The opsional callback parameter allows executing additional logic after the image swap completes.

Tags: javascript Lazy Loading Performance web development Image Optimization

Posted on Fri, 16 Oct 2026 16:23:30 +0000 by Mad_Mike