How to Implement Efficient Image Lazy Loading with Vanilla JavaScript

This guide explains the concept of image lazy loading, how to detect when an image enters the viewport, and provides a complete vanilla‑JavaScript implementation with throttled scroll handling to improve page performance and reduce bandwidth usage.

JavaScript
JavaScript
JavaScript
How to Implement Efficient Image Lazy Loading with Vanilla JavaScript

Definition Image lazy loading, also called delayed loading, loads images only when they enter the viewport, reducing requests, saving bandwidth, speeding up page load, and lowering server load. It improves user experience by avoiding loading large amounts of data at once.

Implementation The challenge is to detect whether an image is needed. In browsers, an image is needed when it appears in the visible area. We check if the image’s bounding rectangle intersects the viewport; if so, we replace its placeholder source with the real URL (image dimensions should be set, e.g., via padding).

Determine if an image is in the viewport:

Viewport height

Distance from the top of the page to the image

Using these two values we can decide whether the image is visible.

var nodes = document.querySelectorAll('img[data-src]'),
    elem = nodes[0],
    rect = elem.getBoundingClientRect(),
    vpHeight = document.documentElement.clientHeight;

if (rect.top < vpHeight && rect.bottom >= 0) {
    console.log('show');
}

After detecting visibility, retrieve the real image URL.

<img src="loading.gif" alt="">
... 
<script>
var src = elem.dataset.src;
</script>

Assign the real URL to the image.

var img = new Image();
img.onload = function () {
    elem.src = img.src;
};
img.src = src;

Full code

var scrollElement = document.querySelector('.page'),
    viewH = document.documentElement.clientHeight;

function lazyload() {
    var nodes = document.querySelectorAll('img[data-src]');
    Array.prototype.forEach.call(nodes, function (item) {
        if (item.dataset.src === '') return;
        var rect = item.getBoundingClientRect();
        if (rect.bottom >= 0 && rect.top < viewH) {
            (function (item) {
                var img = new Image();
                img.onload = function () {
                    item.src = img.src;
                };
                img.src = item.dataset.src;
                item.dataset.src = '';
            })(item);
        }
    });
}
lazyload();

scrollElement.addEventListener('scroll', throttle(lazyload, 500, 1000));

function throttle(fun, delay, time) {
    var timeout,
        startTime = new Date();
    return function () {
        var context = this,
            args = arguments,
            curTime = new Date();
        clearTimeout(timeout);
        if (curTime - startTime >= time) {
            fun.apply(context, args);
            startTime = curTime;
        } else {
            timeout = setTimeout(fun, delay);
        }
    };
}

Demo

For demonstration, the demo adds a 500 ms delay to img.onload. Click to view the original demo.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendperformanceimage-optimizationJavaScriptlazy loadingscroll throttling
JavaScript
Written by

JavaScript

Provides JavaScript enthusiasts with tutorials and experience sharing on web front‑end technologies, including JavaScript, Node.js, Deno, Vue.js, React, Angular, HTML5, CSS3, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.