Speed Deferring Images

defered images and clock

This article will describe a simple way to defer images without jQuery or lazy loading.

One of the main reasons a page loads slowly is images. There is not an internet user anywhere that has not seen an image, slowly loading from top to bottom.

Even as a user watches that image slowly loading, there are often multiple images further down the page that are not visible to that user yet, and they are all loading too.

All these images are competing for the same bandwidth as your page resources such as css and javascript. This means images are getting in the way of providing the initially visible part of your webpage to users as quickly as possible.

This is a well known issue

The main way developers and webmasters have solved this issue is through a method called lazy loading.

Lazing loading images is a solution where as a user scrolls down the page, images are loaded as needed. There are many wonderful things about lazy loading and I use it often, but it has some issues...

Deferring images without lazy loading or jQuery

The truth is that lazy loading images is just a more complicated way of deferring images.

To get back to basics we will be talking about deferring images without lazy loading. But let's first define the stuff that lazy loading is actually doing.

  1. Observing a scroll position
  2. Monitoring scroll position
  3. Reacting to a scroll position
  4. deferring images

In the four things above, only one of them is the deferring of images.

Let's discuss the deferring images part

When a webpage is rendered in a browser the browser will attempt to download all the images it can find on the page. If there are two images on the page, it will download two images. If there are one hundred images on the page it will download all one hundred.

This is default browser behavior. It has to request and download all images.

The only reliable way around this (for all browsers) is to trick the browser into thinking those images aren't there.

The way that is done in lazy loading and elsewhere is to provide a tiny default image in our html, and then switch that default image via javascript to the real image we want to display.

This means that images are marked up something like...

<img src="fake.png" data-src="real-image.png"

When the page is initially loaded, the browser will get the "fake image" once and then that will be the only image the browser sees, so whether you have one image or a hundred, it won't matter because the browser has already downloaded the fake image.

Then via javascript we swap out the fake image with the real one.

When the browser sees that there is a new image in the html, it will now download it.

This relatively simple step can provide amazing results. I recently made a page that took eight seconds to load go down to less than a second using only this method.(we will describe the method in full below with example code)

Understanding the page load

To understand how, when and what method of deferring to use, we need to understand how a page loads. This is good knowledge to have and will only take a minute or two to read.

The image above shows a small webpage loading. The page has a main image, several other images, a css file and a javascript file.

In this rather typical page, every single resource is competing to be downloaded at the same time.

The truth is though, the only thing that needs to be downloaded is the stuff above the dotted line. This is the "above the fold" or the initially visible part of the page.

This means that for the user to see the above the fold content, we only need the html, css, javascript, and the main image.

Let's look how we can make this page load twice (or more) faster than it is now. We should...

Once we do that, we see that the pageload event can occur at a much earlier part of the load.

Now we have just cut a page that was loading 12 items before the page load into a page that only loads four things before the pageload event.

I like that.

It means my adsense ads can show up faster, my users can buy things quicker, and Google thinks I am wonderful.

Let's be real. You know and I know that your pages have dozens and dozens of images, not the few represented here. Make no mistake, this method can make your pages seriously faster. The more images you have the more time you can shave off with this.

Doesn't lazy loading already do this for me?

It does, but there are many situations where lazy loading does not work ideally.

The most common reason people may chose not to defer images via lazy loading is likely the new popular trend of having one page templates or themes.

One page templates

If you have a one page template (this means that your main navigation is not taking you to other pages it is rather taking you to different parts of the same page) and you choose lazy loading, an interesting problem pops up.

Your page loads, the user sees your main navigation, and if they click, they are taken to part of your page that does not have the images loaded yet.

Ewww. I don't like that.

In this case even though your users just used your navigation, they are taken to a place where they will have to wait for an image.

This is where we defer the images without lazy loading

In the scenario of a one page template, there is no reason to do all the things that lazy loading does (observe, monitor and react to a scroll postion).

Why not just defer those images and have them load immediately after the page has loaded?

How to do it

To do this we need to markup our images and add a small and extremely simple javascript. I will show the method I actually use for this site and others. It uses a base 64 image, but do not let that scare you.

The html

<img src="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" data-src="your-image-here">

The javascript

<script>
function init() {
var imgDefer = document.getElementsByTagName('img');
for (var i=0; i<imgDefer.length; i++) {
if(imgDefer[i].getAttribute('data-src')) {
imgDefer[i].setAttribute('src',imgDefer[i].getAttribute('data-src'));
} } }
window.onload = init;
</script>

Usage

For most pages you can simply put the script right before the end body tag in your html. As far as the images go you want to copy the code above (labeled "the html") and replace "your-image-here" with your actual image path.


Patrick Sextonby Patrick Sexton

Defering Images without lazy loading or jQuery