A beach with an umbrella to be lazy underneath.

Websites need to look pretty and be blazing fast. That often means lots of beautiful high-quality images, but they can be pretty enormous to download, making the page slow to load. Images are often one of the 'heaviest' parts of a website, dragging a visitor's experience down instead of brightening it up as intended. If a website feels even a tiny bit unresponsive, that tarnishes your message or brand. Most of us have sat waiting frustratedly for a website to work (especially on mobile), and given up to go elsewhere. Drupal can be configured to deliver appropriately-resized versions, but what's even better than that?

Lazy image loading

Don't send images to be downloaded at all until they're actually going to be seen! Browsers usually download everything for a page, even if it's out of sight 'below the fold'. We know we can do better than that on a modern website, with this technique called lazy image loading.

Lazily loading an image means only sending it for a user to download once they are scrolling it into view. Modern web browsers make this surprisingly simple to achieve for most images, although there are often a few that need special attention. When combined with optimisation from Kraken.io, and other responsive design tricks, performance can sky-rocket again. Check out our case study of NiquesaTravel.com for a great example using this.

Niquesa is a luxury brand for busy people, so the website experience needs to be smooth, even when used on the go over a mobile network. Perhaps more than that, SEO (search engine optimisation) is critical. Their bespoke packages need to show up well in Google searches. Google promotes websites that perform well on mobile devices - so if your site is slow, it needs to be sped up. It's not just that you'll lose out on competitive advantage and tarnish your brand: people simply won't find you.

You can see what Google thinks of your website performance by using their PageSpeed Insights tool. That gives you an overall score and lists specific improvements you can make. Niquesa asked us to boost their score, especially for mobile devices. So we looked to speed up anything slow, and to reduce the amount of things there are to download in the first place. Any website can use that approach too. Lazy image loading speeds up the initial page load, and reduces the amount to download.

This stuff should be standard on most websites nowadays. But many web projects began well before browsers supported this kind of functionality so still need it adding in. As an ever-improving platform, the internet allows you to continually improve your site. There's no need to feel locked in to a slow site! Get in touch with us if you're interested in improving your website with lazy loaded imagery. Who wouldn't want beautiful high-quality media and great performance on any device?

 

Can you teach me to be lazy?

Sure! Rather than using the normal src attribute to hold the image file location, use a data-src attribute. Browsers ignore that, so nothing gets downloaded. We then use the browser's Intersection Observer API to observe when the image is being scrolled up into view. Our javascript can jump in at this point to turn that data-src attribute into a real src attribute, which means the browser will download the real image.

On its own, that wouldn't take very long to set up on most websites. But on top of this, we often go the extra mile to add some extra optimisations. These can take up the majority of the time when applying lazy loading to a website, as they are a great improvement for the user experience, but usually need crafting specifically for each individual project:

  • Images defined via style or srcset attributes (rather than a src attribute) and background images in CSS files, need similar handling. For example, use a data-style or data-srcset attribute.
  • Images that we expect to be immediately in view are excluded from any lazy loading, as it is right to show them immediately.
  • It may be important to keep a placeholder in place of the real image, perhaps either to keep a layout in place or in case javascript is not running. Styling may even need to be tweaked for those cases. Sadly it's not unusual for third-party javascript out of your control to break functionality on a page!
  • Dimensions may need some special handling, as Drupal will often output fixed widths & heights, but responsive design usually dictates that images may need to scale with browser widths. If the real image is not being shown, its aspect ratio may still need to be applied to avoid breaking some layouts.
  • Some design elements, like carousels, hide some images even when they are within the viewport. These can get their own lazy magic. One of our favourite carousel libraries, Slick, supports this with almost no extra work, but many designs or systems will need more careful bespoke attention.

Here is a basic example javascript implementation for Drupal:

(function($) {
  // Set up an intersection observer.
  Drupal.lazy_load_observer = new window.IntersectionObserver(function(entries) {
    for (var i in entries) {
      if (entries.hasOwnProperty(i) && entries[i].isIntersecting) {
        var $element = $(entries[i].target);
        // Take the src value from data-src.
        $element.attr('src', $element.attr('data-src'));
        // Stop observing this image now that it is sorted.
        Drupal.lazy_load_observer.unobserve(entries[i].target);
      }
    }
  },
  {
    // Specify a decent margin around the visible viewport.
    rootMargin: "50% 200%"
  });

  // Get that intersection observer acting on images.
  Drupal.behaviors.lazy_load = {
    attach: function (context, settings) {
      $('img[data-src]', context).once('lazy-load').each(function() {
        Drupal.lazy_load_observer.observe(this);
      });
    }
  };
})(jQuery);

(This does not include a fallback for older browsers. The rootMargin property, which defines how close an element should be to the edge of the viewport before being acted on, might want tweaking for your design.)

Drupal constructs most image HTML tags via its image template, so a hook_preprocess_image can be added to a theme to hook in and change the src attribute to be a data-src attribute. If required, a placeholder image can be used in the src attribute there too. We tend to use a single highly-cacheable transparent 1x1 pixel lightweight image, but sometimes a scaled down version of the 'real' image is more useful.

The lazy loading idea can be applied to any page element, not just images. Videos are a good candidate - and I've even seen ordinary text loaded in on some webpages as you scroll further through long articles. Enjoy being lazier AND faster!

     

    Image: Private beach by Thomas