Optimising speed by lazy loading – without JavaScript

It’s not a surprise that images are one of the heaviest part of a website when it comes to loading. One of the best things you can do to optimise the loading of your website is to lazy load as many images as you can, and now thanks for native Lazy Loading you can do so without using your own JavaScript.

How to asynchronously load images without JavaScript

Asynchronously loading images means that you load images only when they appear in the browser’s viewport (or just before). The benefit of this is that your site will initially load quicker as it doesn’t need to load all the images that cannot be seen within the initial paint of the website.

Thanks to the now well supported native loading attribute you can avoid adding a JavaScript library (or writing your own script) to detect when images are in the viewport to then load them.

Using the loading attribute

There are three possible values that can be used with the loading attribute.

Generally speaking, it would make sense to use the eager value for resources that sit above the fold and the lazy value for resources that sit below the fold. That, or don’t include the loading attribute on images above the fold.

Image markup using the loading attribute

So what does your image markup need to be to use the loading attribute? Here is an example.

<img src="image.jpg" alt="..." width="200" height="200" loading="lazy" />

It is important when using lazy that you specify the image dimensions, either in the width and height attributes or within an inline style. This is important because if they are not set, layout shifts can occur – which is not the best UX.

Using the loading attribute with the picture element

  <source srcset="large.jpg 1x, larger.jpg 2x" media="(min-width: 800px)" />
  <img src="image.jpg" alt="..." />

The browser will decide which image to load from any of the sources. The loading attribute only needs to be included on the fallback element.

Lazy loading support for older browsers

For older browsers that don’t support it, the loading attribute will simple be ignored and your images will load with the rest of the website on initial page visit.

Of course, we should be looking to offer lazy loading to as many website visitors as possible, whatever browser they are on. So, how can we offer this to users on unsupported browsers?

The only way would be to load in our JavaScript fallback to offer the same functionality. What we don’t want to do though is load our script for those who are on supported browsers, as that would make all our work to reduce our load null and void. So what can we do?

Detect if a user is on a supported browser using this snippet.

if ('loading' in HTMLImageElement.prototype) {
  // supported in browser
} else {
  // fetch polyfill/third-party library

Putting it all together

<!-- Let's load this in-viewport image normally -->
<img src="hero.jpg" alt="…">

<!-- Let's lazyload the rest of these images -->
<img data-src="unicorn.jpg" alt="…" loading="lazy" class="lazyload">
<img data-src="cats.jpg" alt="…" loading="lazy" class="lazyload">
<img data-src="dogs.jpg" alt="…" loading="lazy" class="lazyload">

  if ('loading' in HTMLImageElement.prototype) {
    const images = document.querySelectorAll('img[loading="lazy"]');
    images.forEach(img => {
      img.src = img.dataset.src;
  } else {
    // Dynamically import the LazySizes library
    const script = document.createElement('script');
    script.src =

Now we have a solid all round solution for making use of native lazy loading whilst offering a fallback for older browsers that also optimises the images we need to load within a website.

Find this resource useful?

I want everyone to be able to benefit from articles like this.

That's why I need your help in spreading awareness. Please consider telling your fellow developers about the sustainable.dev by sharing a Tweet.

Tweet about the sustainable.dev