Lazy Loading

Why load everything on the web page while it is not (yet) visible? Endless scroll and lazy loading have been used for many years now in social media web sites. 

However, if you take the Umbraco Starter Kit as your (not too bad) starting point for a new web site, you will have to implement this yourself.

In the Starter Kit, we have a Products page. With only a few products showing, this is not a big deal. But what if your product catalog grows and you end up with hundreds of products, each with a 500 KB image. It would really kill the user experience if the page was not fully loaded until every image was downloaded.

So, how to implement lazy loading on the Products page?

The interesting thing is that this can be done in plain vanilla JavaScript.

There are a few relatively steps in the process:

  1. Determine the property that assigns a media item to a HTML element (src if IMG, background-image in a style property in a DIV or A). In the Starter Kit, a style attribute containing the background-image url is used).
  2. Gather all elements of the type that need to be optimized.
  3. Store the particular attribute in a temporary attribute and remove the original attribute.
  4. Create an event listener for a number of events, such as load, scroll and resize. This event listener should check if an image falls within the visible region. If so, re-create the original attribute, copy the value from the temporary attribute and throw the temporary attribute away.
  5. Presto! 

 Below is a code example. Store in a Script document in Umbraco and call the script as the last script from the Products template.

With just a few modifications you could make this work in many other (and non-Umbraco) environments.

// Get all images in article block
// version: 22 Feb 2021 / v1.1
var a_imgs = document.getElementsByClassName("product-grid__item");    
for (var i = 0; i < a_imgs.length; i++ ){
    // clone the value of the attribute style into realstyle and set style to blank
    var realstyle = document.createAttribute("realstyle");
    realstyle.value = a_imgs[i].getAttribute("style");
    a_imgs[i].setAttributeNode(realstyle);
    a_imgs[i].removeAttribute("style");            
}

refresh_handler = function(e) {
var elements = document.querySelectorAll("*[realstyle]");
for (var i = 0; i < elements.length; i++) {
        var boundingClientRect = elements[i].getBoundingClientRect();
        if (elements[i].hasAttribute("realstyle") && boundingClientRect.top < window.innerHeight) {
            elements[i].setAttribute("style", elements[i].getAttribute("realstyle"));
            elements[i].removeAttribute("realstyle");
        }
    }
};

window.addEventListener('scroll', refresh_handler);
window.addEventListener('load', refresh_handler);
window.addEventListener('resize', refresh_handler);