• Utility
  • CORE COMPONENT
  • Taxonomic name: U-LAZYLOAD
  • Added on: v3.2.0 (16/02/18)
  • Updated on: v5.6.0 (20/04/21)

Lazy loading


Design and usage

Normally when a user opens a webpage, the entire page's contents are downloaded and rendered in a single go. While this allows the browser to cache the web page, there's no guarantee that the user will actually view all of the downloaded content. For example, if an entire photo gallery is downloaded, but the user leaves after only viewing the first image, then the result is wasted memory and bandwidth.

Instead of bulk loading all of the content when the page is accessed, content can be loaded when the user accesses the part of the page which requires it. With lazy loading, pages are created with placeholder content which is only replaced with actual content when the user needs it.

Utilising lazy loading techniques can help greatly reduce page sizes and consquentally page loading times. A slow-loading page causes frustration for site visitors, because people are used to having pages load quickly in this day and age. It is important to keep on top of your page speed, as it is a ranking factor in Google's search ranking algorithms and, more importantly, an irritation for visitors. A well designed site should be easy to use and fast to load; if it fails on either of these counts, then you will lose traffic due to frustrated visitors.

How lazy loading works

When someone adds a resource to a web page (image, video, etc.), the resource references a small placeholder. As a user browses the web page, the actual resource replaces the placeholder when the resource becomes visible on the user's screen. For instance, if the user loads a webpage and immediately leaves it, then nothing beyond the top portion of the web page is loaded.

Benefits of lazy loading

  • Lazy loading strikes a balance between optimizing content delivery and streamlining the end user's experience.
  • Users connect to content faster, since only a portion of the website needs to be downloaded when a user first opens it.
  • Businesses see higher customer retention as content is continuously fed to the user, reducing the chances the user will leave the website.
  • Businesses see lower resource costs since content is only delivered when the user needs it, rather than all at once.

Does lazy loading really make a difference?

In the example below, you will see a speed test comparison that compares the same page before and after implementing lazy loading; this has resulted in a reduced page load speed by 3.49 seconds! The page size has also decreased by 597 kilobytes which is a substancial drop. This has been achieved simply by loading in less images on the page thanks to the lazy loading functionality.

Example page built based off the September 2018 Travel Insurance landing page, with and without lazy loading applied to all the images.

  Without lazy loading With lazy loading
Google lighthouse grade 32% 77% (+45%)
Speed index
Time until the page is visibly complete
6.22s 2.73s (-3.49s)
Total page size 1.1MB 529kB (-597kB)
Total # of requests 104 86 (-18)

View working example of page using lazy loading

Code examples

Navigation card - 16:9 full bleed

<a class="l-columns__column m-card m-card-full-bleed m-card-full-bleed--right t-accent-dark" href="..." data-module="u-objectfit">
	<div class="m-card-image m-card-image--16x9">
		<img class="u-lazyload" src="..." data-src="..." decoding="async" width="..." height="..." alt="" />
	</div>
	<div class="m-card-content">
		<div class="m-card-content__inner">
			<p class="m-card-tagline">...</p>
			<p>...</p>
		</div>
		<div class="m-card-content__inner m-card-content__inner--bottom">
			<p class="m-card-readmore"><span>...</span></p>
		</div>
	</div>
</a>

Hero - background image

.m-hero--[ hero name ] {
	background-image: url(...);
}
.m-hero--[ hero name ].is-visible {
	background-image: url(...);
}
<div class="m-hero-wrapper">
	<div class="m-hero t-accent-dark [ Background image class ] [ Modifier ] u-lazyload">
		<div class="m-hero-message">
			<div class="m-hero-message__text ">
				<h1 class="a-heading a-heading--0 a-heading--semibold">...</h1>
				<p class="a-heading a-heading--2 a-heading--light">...</p>
			</div>
			<div class="m-hero-message__button">
				<ul class="m-button-group">
					<li class="m-button-group__item">
						<button class="a-button a-button--primary">...<span class="u-hidden--visually">...</span></button>
					</li>
					<li class="m-button-group__item">
						<button class="a-button a-button--secondary">...<span class="u-hidden--visually">...</span></button>
					</li>
				</ul>
			</div>
		</div>
	</div>
</div>

Hero - inline image

<div class="m-hero-wrapper">
	<div class="m-hero t-accent-dark m-hero--objectfit [ Modifier ]" data-module="u-objectfit">
		<div class="m-hero__image">
			<img class="u-lazyload" src="..." data-src="[ Inline image url ]" decoding="async" width="..." height="..." alt="" />
		</div>
		<div class="m-hero-message">
			<div class="m-hero-message__text">
				<h1 class="a-heading a-heading--0 a-heading--semibold">...</h1>
				<p class="a-heading a-heading--2 a-heading--light">...</p>
			</div>
				<div class="m-hero-message__button">
					<ul class="m-button-group"><li class="m-button-group__item">
						<button class="a-button a-button--primary">...<span class="u-hidden--visually">...</span></button>
					</li>
					<li class="m-button-group__item">
						<button class="a-button a-button--secondary">...<span class="u-hidden--visually">...</span></button>
					</li>
				</ul>
			</div>
		</div>
	</div>
</div>

Development and test

Notes for developers

To include lazy loading on a page, include the data modules data-module="u-lazyload" data-module-load="true" on an element once on the page. This will now enable lazy loading on any elements on the page either initially or added to the page post-load.

Lazy loading works on both inline and background images. The following components have been tested for compatability:

  • Cards
  • Hero banner
  • Images / figures

Only apply lazy loading to images that will not be visible within the initial viewport for the majority of users.

Inline image

Simple inline image

<img class="u-lazyload" src="[ Placeholder URL ]" data-src="[ Final image URL ]" decoding="async" width="..." height="..." alt="..." />

With srcset

<img class="u-lazyload" src="[ Placeholder URL ]" data-src="[ Final image URL ]" data-srcset="[ Final srcset URLs ]" decoding="async" width="..." height="..." alt="..." />

Using picture element

<picture class="u-lazyload">
	<source type="image/webp" srcset="..." media="..." type="..." data-srcset="[ Final srcset URLs ]" />
	...
	<img src="[ Placeholder URL ]" data-src="[ Final image URL ]" decoding="async" width="..." height="..." alt="..." />
</picture>

Support for object-fit polyfills

To ensure that lazy-loading works where you have implemented your own polyfill for object-fit, the class js-objectfit-polyfill needs to be added where the image src needs to be placed as a background image by your polyfill.

The lazy loading code will check if a parent element of the inline image has this class and will then update the CSS background appropriately.

Background image

Background images can also be swapped out; this is acheived by the class is-visible being added by the JavaScript when the element is about to come into view.

The following is an example of how this could be acheived within your CSS file:

.a-example-element {
	background-image: url([ Placeholder URL ]);
}
.a-example-element.is-visible {
	background-image: url([ Final image URL ]);
}
<div class="u-lazyload a-example-element">
	...
<div/>

Placeholder images

A selection of placeholder images that have been highly optimised are available for use. These are offered in both a light (#ccc) and dark (#333) accent colour, and a selection of aspect ratios, depending on the situation they need to be placed within.

Image ratio Image URL
16:9 /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/16-9.svg
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/16-9.png
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/16-9.webp
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-16-9.svg /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-16-9.png /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-16-9.webp
9:16 /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/9-16.svg
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/9-16.png
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/9-16.webp
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-9-16.svg /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-9-16.png /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-9-16.webp
1:1 /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/1-1.svg
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/1-1.png
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/1-1.webp
/assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-1-1.svg /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-1-1.png /assets/[ theme type ]/[ organisation ]/[ theme name ]/icon-library/v2/placeholder/dark-1-1.webp

If possible, generate single-colour placeholder images based on the predominant colour within the image that is being replaced. A two-colour PNG8 file can be very highly compressed and produces better results than using GIF or JPEG.


Notes for testers

For IE10 and below and some other older browsers, placeholder images will not be swapped out when JavaScript is not available.

Component releases

  • Added on: v3.2.0 (16/02/18)
  • Updated on: v5.6.0 (20/04/21)

Latest update:

  • updated: To improve page load and layout times the additional attributes decoding="async", width and height must be set on all inline images.

Full version history

A full history of changes and enhancements detailing all minor and major updates to the component.

View full version history

Want something new in Framework, or to chat about an issue you're having with it?

Contact the team