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>
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);
});
};
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);
}
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);
}
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;
}
So that's all! Here's the link of CodePen. See you soon!
Top comments (1)
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. 👇