DEV Community

Linas Spukas
Linas Spukas

Posted on

Image Lazy-Loading With Pure JavaScript

Half of the application size and file requests takes images. If you want to make your application faster and lighter, it is a good starting point to think about image optimisation.

You can make your application faster by lazy-loading images. Meaning to show them, only when they appear in the viewport of the device or near it. It can be done using the Intersection Observer API.

Intersection Observer

It is a performance API, that notifies you when an element is entering or leaving the viewport. To have the information when to hide or to show elements is very useful. You can use it for analytics to track how much time a user spends by viewing the current element, you can start or stop the video when it reaches a certain point in the view or load more content, like images, when you scroll to the bottom of the page.
Intersection Observers are a very efficient and perfect tool to track scroll events.

To use Intersection Observer we call a constructor and pass a callback function. That callback will run on every element that is being observed. To observe particular elements, we select them and call the observe method on each of them:

<head>
    <style>
        .box {
            border: 1px solid;
            height: 400px;
            width: 500px;
        }
    </style>
</head>

<body>
    <div class="box">1</div>
    <div class="box">2</div>
    <div class="box">3</div>
    <div class="box">4</div>

    <script>
        const io = new IntersectionObserver((entries) =>
            entries.forEach((entry) =>
                console.log(
                    entry.target.innerText + " entered the view: " + entry.isIntersecting
                )
            )
        );

        document.querySelectorAll(".box").forEach((element) => io.observe(element));
    </script>
</body>

If you run this code and check the browser console, you should see all div elements are registered, and on scrolling the page, each of the element prints output when it enters and leaves the viewport.

Lazy-Loading Images

When the browser detects a source attribute in the image tag, it downloads it from the path, parses and renders. By manipulating source and dataset attributes we can decide when to show the image.

The idea behind lazy-loading images is:

  • removing image src attribute or adding a placeholder
  • putting the source link in the dataset attribute
  • call intersection observer on the images
  • when the intersection is detected, take the source from dataset and place in the src

Dataset attributes are an ideal place to store additional information for later access. By placing the actual image path in the data-src, and later picking it and setting to the src attribute we will load the image.

<body>
    <img class="lazy" data-src="lazy-image.jpg">
    <img class="lazy" data-src="lazy-image.jpg">
    <img class="lazy" data-src="lazy-image.jpg">

    <script>
        const io = new IntersectionObserver((entries) =>
            entries.forEach((entry) => {
                // set image source only when it is in the viewport
                if (entry.isIntersecting) {
                    const image = entry.target;
                    // setting image source from the dataset
                    image.src = image.dataset.src;

                    // when image is loaded, we do not need to observe it any more
                    io.unobserve(image);
                }
            })
        );

        document.querySelectorAll(".lazy").forEach((element) => io.observe(element));
    </script>
</body>

That is the most simple example of how to lazy-load images just with pure JavaScript.

Things To Think About It

Image tag size is defined by the picture. If you do not specify the dimensions for it, or put a placeholder for the src attribute, all your images will have 0px size and will be loaded by observer right away.

Intersection Observer API is mostly used for all modern browsers. But if you need support for older ones, you should use a polyfill. Also, a good way would be to check at first if the browser has Intersection Observer. In case it does not, run a fallback code.

Conclusion

Using image lazy-loading will make the page lighter, loading time faster, less usage of browser resources and make the user experience more enjoyable.

Top comments (3)

Collapse
 
fly profile image
joon

Will definitely try this in a future project, currently on the lookout for the most optimized/effective method to lazy load images :)
Thank you for the post!

Collapse
 
czriad001 profile image
czriad001 • Edited

its working on <img data-src="" tag. can i use only <img src="" tag? i used custom php script. so i want to target all img tag & use lazy load for full website header to footer full website. if have time please let me know how to use for full website.
Thank you.

Collapse
 
storrence88 profile image
Steven Torrence

I just implemented something like this in a project last week! Really cool stuff!