Web Dev Simplified Blog

Speed Up Your Site Instantly With Lazy Loaded Images - Advanced Lazy Loading

May 1, 2023

Lazy Loaded Image Example
Lazy Loaded Image Example

Lazy loading images is one of the easiest ways to speed up the load times of your site since the most basic form of lazy loading only requires one line of code. However, there are a few advanced techniques you can use to make your lazy loading look just like the image above with blurred placeholders and a smooth transition from the placeholder to the full image. In this article I will be covering everything you need to know about lazy loading as well as how to create this advanced lazy loading effect.

If you prefer to learn visually, check out the video version of this article.

What Is Lazy Loading?

Lazy loading is a technique used to defer the loading of an asset until it is needed. In the case of images, this means that the image will not be downloaded until the user scrolls to the point where the image is visible on the screen. This is a great way to speed up your site since you are only downloading the images that the user will actually see. This is especially useful for sites with a lot of images since you can save a lot of bandwidth by only downloading the images that the user will actually see.

If you have a fast internet speed or you only ever view sites with small, well optimized images, you may not see the advantage to lazy loading images since you can download all the images almost instantly, but for everyone else lazy loaded images are a game changer. This also isn’t just for people with super slow internet connection either. Images are one of, if not, the largest asset your user will download so even if they have a fast internet connection, lazy loading images can still make a huge difference in the load time of your site.

Basic Lazy Loading

As I mentioned at the start of this article, lazy loading images is as simple as adding a single attribute to your image tag. The loading attribute can be set to lazy to enable lazy loading on the image. The browser will automatically determine when to download the image based on how close the image is to being on the screen.

<img src="image.jpg" loading="lazy" />

All of the images on this page are lazy loaded so you will notice that if you scroll down the page, the images will not load until they are almost on the screen. You can easily see this by viewing the Network tab and filtering to just image requests.

The biggest downside to this basic lazy loading is that the user will see a blank space where the image should be until the image is downloaded. It will look something like the below image.

Basic Lazy Load Flicker Example

This is not an ideal user experience which is why the rest of this article will show you how to take advantage of lazy loading to show a blurred placeholder image until the full image is downloaded.

Advanced Lazy Loading

You may have noticed when looking at the dev tools that there were a bunch of really small images being downloaded. These are the blurry placeholder images that are shown until the full image is downloaded and is the first step to creating this advanced lazy loading effect.

To create a blurry placeholder image you just need to generate a super low resolution version of the image. There are many ways to do this, such as, using a service like BlurHash, manually resizing the image in a tool like Figma, or automatically using a tool like ffmpeg. I will be using ffmpeg to generate the placeholder images for this article since it is the most flexible option and can be automated easily. All I had to do was run the below code on the command line within the directory containing the image I wanted to generate the placeholder image for.

ffmpeg -i imageName.jpg -vf scale=20:-1 imageName-small.jpg

This will generate a placeholder image that is 20 pixels wide and the height will be automatically calculated to maintain the aspect ratio of the original image. You can change the width to whatever you want, but I found that 20 pixels works well for most images and is small enough that it will load nearly instantly even on slow internet connections. My placeholder images were less than 1kB each.

The next step is to create a div and set the background image of that div to our super small image. This will be the placeholder image that is shown until the full image is downloaded. Our code will look something like this.

<div class="blurred-img"></div>
.blurred-img {
  background-image: url(imageName-small.jpg);
  background-repeat: no-repeat;
  background-size: cover;
}
Lazy Loaded Image Example

Most likely your image will not be as large as mine since the blurred-img div is sized based on the size of the content in it. We can easily fix this, though, by adding the img into our div and making sure to hide it by default so we never see it in a half loaded state.

<div class="blurred-img">
  <img src="imageName.jpg" loading="lazy" />
</div>
.blurred-img img {
  opacity: 0;
}

This will give us the effect we are looking for. The blurred effect we are getting automatically is because the super small image is being scaled up automatically by the browser. If you wanted to add more blur you could always use the CSS filter property to add a blur filter to the blurred-img div. I personally, don’t think this is needed, though.

.blurred-img {
  filter: blur(10px);
}

You can even take this a step further by adding in a pulsing animation to the placeholder image. This will make it even more obvious that the image is loading.

.blurred-img::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0;
  animation: pulse 2.5s infinite;
  background-color: white;
}

@keyframes pulse {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 0.1;
  }
  100% {
    opacity: 0;
  }
}
Lazy Loaded Image Example

Now the only thing left to do is to fade in the full image once it is loaded. This is a little bit more complicated than the rest of the code we have written so far, since it requires us to use JavaScript, but it is still pretty simple. We just need to add an event listener to the image that will fire once the image is loaded and then we can fade in the image.

<div class="blurred-img">
  <img src="imageName.jpg" loading="lazy" />
</div>
const blurredImageDiv = document.querySelector(".blurred-img")
const img = blurredImageDiv.querySelector("img")
function loaded() {
  blurredImageDiv.classList.add("loaded")
}

if (img.complete) {
  loaded()
} else {
  img.addEventListener("load", loaded)
}
.blurred-img {
  background-repeat: no-repeat;
  background-size: cover;
}

.blurred-img::before {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0;
  animation: pulse 2.5s infinite;
  background-color: var(--text-color);
}

@keyframes pulse {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 0.1;
  }
  100% {
    opacity: 0;
  }
}

.blurred-img.loaded::before {
  animation: none;
  content: none;
}

.blurred-img img {
  opacity: 0;
  transition: opacity 250ms ease-in-out;
}

.blurred-img.loaded img {
  opacity: 1;
}

This is a lot of code so I will break it down step by step. In the JavaScript code we are selecting the blurred-img div and then selecting the img within that div. We are then checking the complete property of the img to see if it has loaded yet. If this is true it means the image has already loaded so we can just call the loaded function. If it is false, though, we need to add an event listener to the img that will fire once the image is loaded and then call the loaded function. The loaded function simply adds the loaded class to the blurred-img div.

In the CSS we have a few changes to the code. First we removed the animation/content from the blurred-img::before element. This will stop the pulsing animation once the image is loaded. We also added a transition to the img element so that it will gently fade in when the loaded class is added to the blurred-img div. Lastly, we change the opacity of the img to 1 so it is visible when it is loaded.

Doing all of this will result in the following image that will load a blurred placeholder image until the full image is loaded and then fade in the full image. You can play around with your network speed in the dev tools to see the loading animation in action.

Lazy Loaded Image Example

Conclusion

Lazy loading images is a pretty simple technique that can be used to improve the user experience of your website. The simplest version of lazy loading only takes a single line of code, but it can be expanded to some pretty neat loading techniques with not too much additional code.