Yes, I’m Lazy

Chris Colebourn posted July 24, 2015

The faster a web page loads the more likely people will use it. 80% of the time spent by a user waiting for a page to render is outside the server. The time is divided between downloading components, parsing, rendering content and executing scripts. For most pages, downloading is the largest component. Downloading content has two parts. The number of HTTP requests that need to be made and the total size needed to be downloaded. There are a number of techniques to reduce the number of HTTP requests: image maps, sprites, combining CSS and JavaScript. None of those techniques attempt to reduce the size of the download. A few approaches do exist to reduce the size of the download such as compression and obfuscation. The best way is to skip it in the first place.

What is Lazy Loading and How Does it Help

Lazy loading is a technique that allows the browser to defer the downloading and/or the rendering of content. Lazy loading is most useful with images. Our web pages contain many images accounting for the majority of the downloaded content. The concept is simple. Any image that is below the fold (the visible area when the page first loads) is a candidate for loading after the page initially loads. If the user never scrolls the page they don’t pay for the download cost of the image. For longer web pages this can reduce the number of images needed at page load time by 50% or more. If the user does scroll they only need to download the images when needed.

How To Lazy Load Images

Intuitively one may consider a JavaScript solution as follows:

On domready:

  1. Get all the image elements in the document.
  2. Calculate the horizontal and vertical visible areas.
  3. Iterate over all the images, anything outside of that is candidate for lazy loading.
  4. Replace each image to be lazy loaded with an empty span to hold its spot.
  5. Start a timer thread to wake up every 500ms.
In the Timer:

  1. Calculate the current visible area.
  2. Iterate over all the image candidates for lazy loading.
  3. For any image now visible (or soon visible, say within 100-200px) replace the span with the img element again. This will trigger the browser to load and render it.
  4. If there are still images which haven’t been loaded then reset the timer to wake again in 500ms.

The problem is this approach doesn’t work. Many browsers read the img source when parsing the HTML and will begin to download the image before you can get the JavaScript to replace it. The true solution is to split the logic between server side and client side. Here is the updated approach:

In server side code:

  1. Create a map of all the images to be lazy loaded. You can’t know the visible area here so you’ll need to use your best judgment.
  2. Instead of writing image tags directly into the HTML write the span tags with corresponding ID’s to those in the map.
On domready:

  1. No need to get all the images, the server side code already calculated what to lazy load.
  2. Calculate the horizontal and vertical visible areas.
  3. Iterate over all the lazy load images.
  4. If it is outside the visible scroll area do nothing.
  5. If it is visible (the server guessed wrong) replace the span with the img to load it now.
  6. Start a timer thread to wake up every 500ms.
The timer logic is the same as above.

This works great for images but what about background images applied via CSS?

Background Images

Background images are used frequently, specifically when using sprites. Any good lazy loading technique should be able to handle CSS background images. To do so the above approach needs to be extended. In order to lazy load an image we removed the element from the DOM. The same approach can be applied to an element with a background image. Replace the HTML markup that uses the background image with a marker element (a span with a unique id). Stash that HTML markup in a JavaScript map again. Instead of replacing the span with an img element, replace the span with the HTML markup.

Conclusion

We have seen significant speed-up of our page load times be lazy loading images below the fold. Users who don’t scroll down the page or only scroll part way down the page don’t’ pay for loading content they don’t need. Making the page faster gives users a much better user experience.

Leave a Reply

Your email address will not be published. Required fields are marked *