In the previous Lazy Loading Introduction chapter we looked at the background of lazy loading in great detail and saw its history coupled with its significance in modern day web and app designing. If you somehow missed it then consider reading it first before proceeding any further.

In this chapter we will specifically be looking over some fundamental concepts involved in lazy loading together with exploring how it operates at the basic level.

Let's begin!

How lazy loading works

When we are talking about lazy loading we are talking about scroll events. And not only this - we are also talking about element offsets, usually from the top of the page, determining when each image will be loaded into view.

Since both scroll events and element offsets are a concern of Javascript it turns out that the heart of lazy loading lies in this scripting language. For CSS in lazy loading there isn't really much to discover, except for in the Fade Effect chapter.

So let's go step-wise into more detail on how lazy loading operates at the basic level.

  1. We start by calculating the top offsets of all the elements we need to lazy load.
  2. Then for each element we assign a scroll event that will track the current scroll bar's position against its offset.
  3. When the condition in the event is met, and the element appears into view, the corresponding event is removed from the listener stack and the image is loaded into view.

And this is lazy loading at the very basic level.

There are obviously a lot of things which we can, and definitely will, add in this basic algorithm to make our lazy loader efficient, performant and stylish, but this is the foundation for all those variants. We can also couple it with modern interfaces such as the IntersectionObserver() API to get the most out of supporting devices as we will see in the Intersection Observer in Lazy Loading chapter. In short, there is a lot to cover as of yet!

For now at least, you shall be comfortable in understanding how lazy loading works at this basic level, since, this understanding will form the foundational basis for you to be able to comprehend some awaiting concepts.

With this done let's move over to laying out the structure for the loader.

HTML - building blocks

The class attribute

Before beginning to build anything on the web we first need to think for a moment on how its HTML will be layed out. Thought is the first process in any program development.

So let's start to think on what would need for a lazy loader.

Firstly we need something indicating that the underlying element shall be lazy loaded. Any thoughts on how can we get this done?

Well this can very easily be done using an HTML class.

All the elements with the class .lazy shall be put in the process to be lazy loaded, in our algorithm. And with a class we get the advantage of being able to fetch all the concerned elements in Javascript easily using class based selection methods like getElementsByClassname() and querySelectorAll()

Following we illustrate this idea and encapsulate the img element within a div container of class .lazy.

<div class="lazy"><img class="lazy-img" src="image.png" /></div>
Now we know that this element has to be lazy loaded!

data-src attribute

The second thing we need to do in our loader's HTML is to remove the src attribute from the img element. Can you think why we need to do this?

If we have the src attribute on <img> elements they will be loaded regardless of whether they are in the viewport or not. In short the whole point of lazy loading becomes useless with src, and hence we need to remove it.

But if we remove the src attribute it, we will potentially lose the source of an image, from where it needs to be fetched from. Where can we save the source of the image? Further if we remove src how can we load an image? In HTML images can only be loaded if they have a src attribute!

Now what? Well the solution is pretty simple.

We wait till the moment an image without src is scrolled into the viewport, after which we assign it a src attribute with the corresponding url value, to fetch the image from. The place where we get the value to assign to src is the data-src attribute.

The attribute serves to just store the source url of an image its on, which will be assigned to src at the image's appearance in the viewport.

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

Now many people tend to think that data-src is some dedicated attribute for this purpose but in reality it's not! We can use any other attribute we like - the idea is just to store the actual URL to fetch an image from, that's it. But here are some benefits of using data-src instead.

Benefits with the data-src attribute

The benefits in using data-src are that firstly the name sounds pretty familiar to src i.e it gives us the feel of a source URL, and secondly Javascript has a dedicated dataset property to fetch data- attributes.

Therefore although we can use any other attribute we like, data-src sounds similar to src and has good JavaScript support. So we move on with using it.

And this all we need to do in the HTML for our lazy loader.

CSS - styling is always green!

As said before, there isn't really much to explore in CSS for lazy loaders except for in the Fade Effect chapter where we add a transitional fade effect before loading images into view.

For now we can give a background-color to .lazy elements to indicate that the vacant space is for an image about to be loaded. Without a background-color users might take the white space as white space only.

Moreover we will set display: inline-block on .lazy to make it fit its image.

.lazy {
    background-color: #eee;
    display: inline-block

And this is it - so do you agree that there wasn't almost anything to discover in CSS!

Moving on

So by this point we have successfully laid out the stucture we will need for our lazy loader, before moving over to its scripting. In the next chapter we will discover the actual logic behind the operation of this loader and construct an extremely simple example with just a single image to lazy load.

We consider a single image to let things remain manageable at this novice stage; things can get quite complex when multiple images are to be dealt with.

Anyways it's always good, and in fact the best way, to start from simpler and smaller problems and build up from them to solve a more complicated one. We can't really approach a tangled task rightaway! Therefore before moving on to the next chapter just make sure that you are completely comfortable with this one.