HTML Images - Eager and Lazy Loading

Chapter 26 25 mins

Learning outcomes:

  1. What is eager loading
  2. What is lazy loading
  3. The loading attribute of <img>
  4. Examples of the loading attribute
  5. Use cases of eager loading
  6. Don't use lazy loading all the time!

Introduction

In the previous chapter, HTML Images — Basics, we got to explore some basic concept underpinning the usage of the <img> element in HTML. We saw the very core src attribute, the alt attribute, a note on copyrights and hotlinking images, and a bunch of other useful stuff.

Lately, over the years, this basic <img> element has gotten a lot of bells and whistles. One that we'll cover in this chapter is <img>'s loading attribute which essentially allows us to control the way in which an image is loaded by the browser.

We'll explore a great number of details regarding the loading attribute including but not limited to what is meant by eager loading; how it differs from lazy loading; the possible values of the loading attribute; cases where eager loading is desirable; and finally, why lazy loading shouldn't be done always.

What is eager vs. lazy loading?

After we visit a webpage, when the browser is done parsing the HTML delivered, it then starts to create the HTML document to be ultimately rendered on the screen.

This phase involves dispatching the necessary requests for any external stylesheets, scripts, icons, and suchlike resources required for the rendering of the document.

Amongst these resources are images, including those represented by the <img> element.

Now, by default, as soon as an image (<img> element in this case) is encountered in the HTML, a request for it is immediately sent to the concerned authority (which might be a web server or simply the local filesystem, in our case).

This behavior is referred to as eagerly loading the image, or simply as eager loading.

Eager loading refers to a loading behavior exhibited by the browser whereby the loading of a resource is initiated as soon as it is encountered in the HTML.

As the definition suggests, eager loading doesn't just apply to images; it encompasses other resources — stylesheets, scripts, iframes, and so on — as well. However, for now, we'll only concern ourselves with image resources.

The opposite of this behavior is to load an image not as soon as it's encountered in the HTML but as soon as there is a real need for it in the browser. Typically this need arises as a result of the image showing up in the viewport.

This behavior is referred to as lazily loading the image, or simply as lazy loading.

Lazy loading refers to a loading behavior exhibited by the browser whereby the loading of a resource is initiated as soon as there is a real need of the resource.

For example, imagine we have a webpage with three images just before the footer section of the page. The page itself is quite long and so the three images are all not initially visible on the front as soon as the webpage loads.

Lazily loading these images would mean that the browser initiates their loading only when they come near the viewport, after having scrolled the webpage for quite some time.

In contrast, eagerly loading them would mean that despite the fact that they aren't visible above the fold initially, they get loaded by the browser (as soon as they are encountered in the HTML code).

So which one is better: eager loading or lazy loading?

Well, honestly, it won't be correct to deem one as being superior over the other. Lazy loading is sometimes good, sometimes not. Eager loading is sometimes good, sometimes not.

It entirely depends on the problem that we have at hand — the problem might best be solved using eager loading or equally by using lazy loading.

As this chapter will unfold, there are pros and cons to both these approaches of loading images in HTML documents.

The loading attribute of <img>

Back in the day, when HTML was void of many cool features, eagerly and lazily loading images was still a thing on the web albeit from the court of JavaScript. There was simply no standard way to control the loading behavior of an image through HTML.

However, with the arrival of the loading attribute in HTML, in particular, for the <img> element (and the <iframe> element as well), this power came natively to HTML.

Now, developers could control the loading behavior exhibited upon an image directly from within the HTML; no need to rely upon complex JavaScript.

Even though loading allows one to control the loading behavior of an image from within the HTML, there still are use cases for doing so using JavaScript. That is, when one needs more control over the loading patterns does JavaScript make for a better candidate.

The loading attribute of an <img> element has two possible values:

  • eager — means that the loading should be eager.
  • lazy — means that the loading should be lazy.

Quite simple values for loading, aren't they?

In case loading is omitted from an <img> element, the default behavior is to eagerly load the image, that is, the same as when we set loading="eager".

Let's now see some examples to help understand eager vs. lazy loading much better.

Examples of loading

Before we can demonstrate the loading attribute in some real action, we need to set the stage for doing so.

And this basically requires us to create an HTML document with a section emulating a long piece of content (on a real webpage) both preceded and followed by two different images.

Here's the document's markup, showing only the contents of <body>:

<h1>Demonstrating the 'loading' attribute</h1>

<p>Here we have an image:</p>
<img src="./html.jpg">

<div style="height: 3000px;background-color: #eee">
   <p>This section represents a very long piece of content on a typical webpage out there.</p>
</div>

<p>Here we have another image:</p>
<img src="./html2.jpg">

After the main headline, we have an image, labelled via a preceding paragraph, followed by a large section, followed by a similar paragraph-and-image part, this time referring to a different image.

Right now, as stated earlier, both the images are eagerly loaded because they don't have the loading attribute set on them.

Let's open up this webpage and inspect some details of what is and/or is not loaded:

Live Example

Once you're on the webpage, press Ctrl + Shift + I on your keyboard, for we're about to get a little bit technical and explore a new tool to add to our arsenal of skills.

This launches the browser's Developer Tools window.

In simple words, as per the name, Developer Tools is a 'provision of tools for developers'.

How simple was that. But obviously this definition does very little in explaining the real purpose behind Developer Tools, right?

So defining it squarely:

A browser's Developer Tools is essentially an envionment comprised of a set of tools that allow us to inspect, debug, performance-test, monitor, and programatically interact with a webpage, amongst many other things.

In our case, for our webpage meant to eventually demonstrate the workings of the loading attribute, we're going to focus on the Network tab where we get to monitor all the resources that are requested by the browser for the underlying webpage.

This will help us determine when and where exactly do our <img> elements get initiated for a load.

So, coming back to the discussion, if you've not opened up the Developer Tools, press Ctrl + Shift + I to do so, and then navigate to the Network tab from the top list of tabs.

While within this tab, press Ctrl + R (or F5) on your keyboard in order to reload the webpage. This is so that we can get a fresh overview of which resources are requested by the webpage from the very beginning.

As the figure below shows, the moment we perform a refresh, two requests are dispatched for our images: one for html.jpeg and one for html2.jpg:

Both images loaded initially
Both images loaded initially

Notice that we didn't scroll the webpage to bring the second image, html2.jpg, into the viewport, yet the browser dispatched a request for it too.

This is an instance of eager loading, whereby the browser doesn't care whether or not an image is in view — if it's encountered in the HTML, just go on and get it loaded. Period.

Now, let's make some changes to our HTML and see the result.

We'll simply change the second <img> element to rather load lazily, by setting loading="lazy" on it:

<h1>Demonstrating the 'loading' attribute</h1>

<p>Here we have an image:</p>
<img src="./html.jpg">

<div style="height: 3000px;background-color: #eee">
   <p>This section represents a very long piece of content on a typical webpage out there.</p>
</div>

<p>Here we have another image:</p>
<img loading="lazy" src="./html2.jpg">

With this, let's get back to the Network tab in the Developer Tools and trigger a reload there again (using Ctrl + R).

Here's what we see in resources table this time:

Only one image loaded initially
Only one image loaded initially

Only the first image, html.jpeg — the one that is initially in the view — is loaded, not the second one.

This is because the second image is way below the viewport and can only come there after some decent amount of scrolling is done.

Let's do this scrolling now and see what happens in the Network tab (there's no need to reload this time):

The second image loaded after scrolling some pixels
The second image loaded after scrolling some pixels

As we scroll the page for a short while, way before the second image is even close to the viewport, the image gets loaded, as marked above.

Now, before anything, you might be thinking that this is strange behavior; the image didn't show up in the viewport yet it is loaded? What's going on?

Well, it's true that browsers tend to load lazily-loaded images way before the point where they actually show up in the viewport.

"Why?" you ask. Simply to have the images ready when we eventually get to them.

Loading images only when they enter the viewport might not be the best choice

Loading images only when they actually enter the viewport might seem like the best choice in the first glance but really it isn't that desirable, quite often. It might lead to a not-so-good user experience (UX).

This holds especially if the images are large in size (which means that they'll take some time to load).

In this case, beginning the loading way before a large-sized image actually shows up in the viewport gives the browser a good amount of time to load the image while the user is engaged in reading the content prior to the image on the webpage.

Then, once the user is done with his reading, the image is ready with its display, thanks to the initiation of loading the image long before actually showing up in the viewport.

Almost all mainstreams browsers initiate the loading of loading="lazy" images long before they actually enter the viewport — to deliver a better UX.

This is one of the reasons why some developers might prefer JavaScript-powered lazy loading over this HTML-powered one — to have more control over when a lazy image is loaded.

Eager loading is sometimes useful

While lazy loading has many virtues to it, this does tend to put a bad light on eager loading.

"Eager loading...Oh it's just very bad. Don't do it!" We might think in this very way because, honestly, on the outskirts, lazy loading has every good trait to it.

Load images only when necessary, save the user's computing resources, save the server's computing resources, deliver a great UX...what else can we possibly ask for?

Wait. Let's not get too carried away looking at the shiny features of lazy loading. Let's ask ourselves the question again that is eager loading useful ever?

Turns out, yes, eager loading is useful sometimes.

Interested to see when? Let's find out.

Essentially, whenever we have critical resources (or critical images in our case), we MUST eagerly load them.

A critical resource is a resource that is necessary for rendering the initial view of a webpage in the browser

Said in other words, whenever we have a resource that is required for the initial view of a webpage in the viewport, we must eagerly load it.

But why? What's so special about critical resources that they must NOT be lazily loaded?

Everything!

Delaying the loading of a critical resource by lazily loading it means that the browser has to wait for some time before it can determine whether the resource is really required or not.

Since we already know that the resource is definitely needed for the underlying document's initial view in the browser, this programmatic determination (by the browser) of whether to load or not load the resource effectively wastes some time and comes at the cost of rendering incomplete views.

When we know that a resource is going to be needed 110%, which holds for a critical resource, why leave this out for the browser to figure out again. Doesn't make much sense, if at all.

Going back to our example, notice how we didn't set loading="lazy" on the first image, the one that was displayed above the fold as the webpage loaded:

<h1>Demonstrating the 'loading' attribute</h1>

<p>Here we have an image:</p>
<img src="./html.jpg"> <!-- A critical resource -->
<div style="height: 3000px;background-color: #eee"> <p>This section represents a very long piece of content on a typical webpage out there.</p> </div> <p>Here we have another image:</p> <img loading="lazy" src="./html2.jpg">

This image is a perfect example of a critical resource — it's required in the initial view of the webpage — and is, therefore, eagerly loaded by omitting the application of loading on it.

Remember, when loading is not set on an <img> element, it is eagerly loaded.

Don't use lazy loading all the time!

This section is related to the previous one in getting us to realize that, in programming, we have to always see whether a good thing is really going to be good for the good.

Wait what? Ignore that. Let's get to the point.

As we stated earlier, there are some cases where eager loading is desirable. That is, when we have critical resources that are absolutely vital for the correct rendering of the initial view of a webpage.

So does this mean that whenever we have non-critical resources, ones that aren't a part of a webpage's initial view, we should opt for lazy loading?

Clearly no. We don't need to go very far off in justifying this; a familiar example follows.

As you'll probably know, almost every website these days brands itself by having a logo (an image) in the header section of the webpage as well as in the footer section.

Now, the case of the logo in the header is very simple — it's a critical image and so should be loaded rightaway (i.e. eagerly). The case, however, of the logo in the footer isn't that simple. Or is it simple?

Well, turns out, the case for the logo in the footer is simple as well!

A logo file typically is just a few kilobytes (KBs). There's certainly NO point in lazily loading the logo in the footer section of a webpage because there isn't a big data saving that we'll get here. In fact, the overhead of monitoring the webpage for lazily loading the logo in the footer would be almost the same as, or even more than, the overhead of loading those extra bytes eagerly.

The same goes for social media icons in the footer section of a webpage — another really common thing these days. Again, icons are typically worth a handful of KBs and, henceforth, also fail to be an ideal candidate for lazy loading. There isn't much that we'll get by lazily loading icons in the footer, or possibly anywhere on a webpage.

So, to boil it down, while the logo in the footer of a webpage or some icons here and there might not be critical resources and, likewise, not necessary for the initial view of the webpage, they still don't quality as the perfect candidates for lazy loading.

As a rule of thumb: Don't use lazy loading all the time!

Always see whether what you're lazily loading pays you and your user off in the form of saving resources (somewhat considerably) and delivering a good UX. If yes, then go for it. If no, then eager loading is the best call.

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage