DEV Community

Cover image for Lazy Load Images with Vanilla Javascript
Guim
Guim

Posted on • Updated on

Lazy Load Images with Vanilla Javascript

What is Lazy Loading?

Surely many of you have already heard that Google Chrome is going to add Lazy Loading in a native way with HTML tags, for images and iframes.

What Lazy Loading basically means is not to load the content of these images until the user does not have them in the field of view. In this way, an image located at the end of the web page will never be loaded if the user does not reach that point. With this solution, we save loading time and gain speed.

In this tutorial we'll lazy load 30 images, previously fetched from an API. First, we'll write the HTML, then the JS code and finally we'll implement some basic CSS to have a beautiful result. Here you have a demo:

Our HTML skeleton

This is our index.html file. It just has a title, a loading spinner and an empty div where we'll put all the images from the API.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Lazy Loading Images</title>

    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <h1>Lazy Loading Images</h1>

    <!-- Images Container -->
    <div id="imagesContainer"></div>

    <!-- Loading spinner -->
    <div class="lds-roller" id="lds-roller">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>

    <!-- Our custom JS code -->
    <script src="main.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

At this point, our page is empty. Let's create our main.js file, grab some images and lazy load them.

Here is where the magic happens

As this file will be more complex, let's split the code into smaller parts so we can deeply understand each of them. All of the following code it's written in the main.js file.

window.onload = () => {
  // Get 30 random images
  fetch('https://picsum.photos/v2/list?limit=30')
    .then(function(response) {
      return response.json();
    })
    .then(function(myJson) {
      // Call the createImages function to generate the HTML code
      createImages(myJson);
      // Remove the loading spinner
      document.getElementById('lds-roller').remove();
    })
    .catch(err => {
      console.log(err);
    });
};
Enter fullscreen mode Exit fullscreen mode

This first function will be triggered ones the window is ready. We use the fetch API to get the images from an external API. This API response us with a JSON file containing all the url's to the images. With this url's we can now create our HTML code.

function createImages(imgs) {
  for (let i of imgs) {
    // Create an image HTML tag
    const image = document.createElement('img');
    image.setAttribute('data-lazy', i.download_url);
    image.classList.add('lazy-loading');
    document.getElementById('imagesContainer').appendChild(image);
  }
  // Sets an observer for each image
  lazyTargets = document.querySelectorAll('.lazy-loading');
  lazyTargets.forEach(lazyLoad);
}
Enter fullscreen mode Exit fullscreen mode

Note that we're not setting the src attribute of the images. We're creating a data-lazy one. This way, the images don't request any data when they are created. Now let's do the lazy-loading function. This function will use the intersection observer API to know when each image is on the view. Then it'll replace the src attribute with the data-lazy one.

function lazyLoad(target) {
  const obs = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        const src = img.getAttribute('data-lazy');

        img.setAttribute('src', src);
        img.classList.add('fadeIn');

        observer.disconnect();
      }
    });
  });
  obs.observe(target);
}
Enter fullscreen mode Exit fullscreen mode

Let's make it pretty

Now I've put some basic CSS to make things prettier. The file referenced in the HTML is style.css.

html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
}

h1 {
  text-align: center;
  font-family: sans-serif;
  font-weight: 200;
}

#imagesContainer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin: auto;
  width: 680px;
}

#imagesContainer img {
  width: 300px;
  min-height: 200px;
  margin: 20px;
  box-shadow: 5px 10px 15px;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

.fadeIn {
  animation-name: fadeIn;
  animation-duration: 3s;
}
Enter fullscreen mode Exit fullscreen mode

So that's all! Here's the link of CodePen. See you soon!

Top comments (1)

Collapse
 
nickytonline profile image
Nick Taylor • Edited

There's also native lazy loading coming to Chromium based browsers and hopefully Firefox eventually as well. Still early days but exciting. @addyosmani has a great write up about it. 👇