Introduction

In the previous Basic Concepts chapter we layed out the HTML and CSS for our lazy loader and it is now that we will be looking over how the JavaScript works. We will be considering the most basic lazy loading algorithm discussed previously and progressively build on it with every subsequent chapter.

We always need to start simple before going complex. This is the principle to be followed in many practical applications even programming.

Anyways let's begin exploring a simple lazy loader.

Revisiting the HTML

Let's revisit the HTML we established in the previous chapter to get a better idea of how we will layout our script.

<div class="lazy"><img class="lazy-img" data-src="image.png" /></div>

We have a class .lazy which will help us in fetching all the image elements to be lazy loaded and a data-src attribute on <img> to just temporarily store the URL of the image.

With this HTML we will now construct a demo HTML page for a fully functional and a fairly basic lazy loader.

Following we add a div element before the .lazy container and give it a significantly large height value to emulate the presence of some content before the lazy image. We want to make the loading feature look more obvious.

<div style="height: 800px;background-color: #eee">A large div</div>
<div class="lazy"><img class="lazy-img" data-src="image.png" /></div>

With this div (and it significant height) the lazy image can go below-the-fold, and get our lazy loading algorithm into action.

If you don't know what is above-the-fold or below-the-fold consider reading this article on the difference between above- and below-the-fold.

So now with a good example set up let's finally move over to the real part i.e JavaScript coding.

Offset calculations

As highlighted earlier, the whole esscence of lazy loading is element offsets and scroll events. Likewise let's start by exploring offsets first.

The offsets we are concerned with in this chapter are the positions of elements relative to the top or left of the HTML document. For a detailed guide to offsets read our Element Offsets chapter which teaches the concept from the crust to the core.

Top offsets are the distances of elements from the top of the document whereas left offsets are the distances from the left of the document.

Knowing an offset for an element means that we know where the element is from the top of the page and this helps us to track the point at which it appears into the viewport.

So let's write the code to record our lazy image's top offset. We'll assume we have only a single image to lazy load and will consequently write code for only one image. This will keep things easy and straightforward. But first let's take you through a small test.

Which of the following can we use to get the top offset of our lazy image?
getBoundingClientRect() method
offsetParent property
style.top property

When calculating the offset of an element, there is a chance that the page is scrolled automatically before the calculation is made.

In this case the offset calculated using getBoundingClientRect() won't be correct.

What can we do to rectify this issue?
Add the amount of scroll done in getBoundingClientRect().top
Subtract the amount of scroll from getBoundingClientRect().top
Read the Bounding Box chapter to understand how the method getBoundingClientRect() works.

Consider the following code:

var lazyCont = document.getElementsByClassName("lazy")[0];
var lazyImage = document.getElementsByClassName("lazy-img")[0];
var offset = lazyCont.getBoundingClientRect().top + window.pageYOffset;

lazyCont holds the image's container to be lazy loaded whereas lazyImage holds the actual image.

offset calculates its offset from the top of the document (in pixels). window.pageYOffset is added to counter to the case if the browser scrolls the webpage automatically before the call of getBoundingClientRect().top.

Adding the src attribute

With the offset calculated now we are left with adding a scroll event that compares the distance scrolled with the offset value and once it exceeds the offset, adds a src attribute to our image. The value of src will be taken from data-src. Implementing all this we get the following.

offset = offset - window.innerHeight
window.onscroll = function() {
    if (window.pageYOffset > offset) {
        // the image is appearing in the viewport
        lazyImage.src = lazyImage.dataset.src
    }
}

offset - window.innerHeight calculates the amount of scroll that would've to be performed before the image enters the viewport. It basically calculates the offset of an image from the bottom edge of the viewport.

The whole conditional in line 2 checks for whether the image has begun to appear in the viewport and once it does begin to, it's given the src attribute (line 5). This causes a request to be made for the image's source and consequently the image to be loaded into view.

This marks the completion of our basic lazy loading algorithm. Let's recap the steps very quickly.

  1. Calculate top offset of the image.
  2. Subtract viewport's height from it and save value in offset.
  3. Assign scroll event to window.
  4. Add a conditional to check for when scrolled more than offset.
  5. When condition met assign data-src value to src.

And here we have a full fledge, perfectly working lazy loader which will as said earlier form the foundational basis for the coming advanced chapters.

Simple Lazy Loader