Search code examples
htmlcsslazy-loading

Image native lazy loading for horizontal scroll


Native lazy loading works just fine for vertical scrolling. But I found that it doesn't when there is a horizontal scroll with an overflow-x. In that case, all the images get loaded, even if they have a fixed size.

Is that working as designed, or can it be fixed?


Solution

  • Native lazy loading in browsers is primarily designed for vertical scrolling scenarios. When dealing with horizontal scrolling using overflow-x, the browser may load all images to ensure smooth scrolling and avoid layout shifts, which is why all the images get loaded even if they have a fixed size. Always Use IntersectionObserver to detect when images enter the viewport and load them. If IntersectionObserver is not supported, fall back to a manual scroll event listener.

    Example CSS for you;

    document.addEventListener("DOMContentLoaded", function() {
        let 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 {
            // Fallback for browsers that do not support IntersectionObserver
            let active = false;
    
            const lazyLoad = function() {
                if (active === false) {
                    active = true;
    
                    setTimeout(function() {
                        lazyImages.forEach(function(lazyImage) {
                            if ((lazyImage.getBoundingClientRect().left <= window.innerWidth && lazyImage.getBoundingClientRect().right >= 0)) {
                                lazyImage.src = lazyImage.dataset.src;
                                lazyImage.classList.remove("lazy");
    
                                lazyImages = lazyImages.filter(function(image) {
                                    return image !== lazyImage;
                                });
    
                                if (lazyImages.length === 0) {
                                    document.removeEventListener("scroll", lazyLoad);
                                    window.removeEventListener("resize", lazyLoad);
                                    window.removeEventListener("orientationchange", lazyLoad);
                                }
                            }
                        });
    
                        active = false;
                    }, 200);
                }
            };
    
            document.addEventListener("scroll", lazyLoad);
            window.addEventListener("resize", lazyLoad);
            window.addEventListener("orientationchange", lazyLoad);
        }
    });
    .scroll-container {
        display: flex;
        overflow-x: auto;
        white-space: nowrap;
    }
    
    .scroll-container img {
        width: 200px; /*you can use any fixed size*/
        height: auto;
        display: inline-block;
    }
    <div class="scroll-container">
        <img data-src="https://2.img-dpreview.com/files/p/E~C1000x0S4000x4000T1200x1200~articles/3925134721/0266554465.jpeg" alt="Image 1" class="lazy">
        <img data-src="https://2.img-dpreview.com/files/p/E~C1000x0S4000x4000T1200x1200~articles/3925134721/0266554465.jpeg" alt="Image 2" class="lazy">
        more here. ...
    </div>