Eric Niquette UI, UX, Accessibility

Fixing issues with lazy loaded images and anchor targets

Published Updated

Lazy-loading images is an easy way to save on bandwidth and reduce load times but when not implemented correctly can also cause layout shifting and break anchor targeting.

What is lazy loading?

Introduced in HTML5, lazy loading is a technique that optimizes loading time by deferring data that is not visible to the user, typically found beyond the viewport. The technique improves loading performance and provides an overall smoother experience. Lazy loading is typically applied to images and inline frames but can also be applied to other elements with various techniques.

By setting an image's loading attribute to lazy, the browser is instructed to delay the image's load until the user reaches a certain threshold, determined by the browser and based on the user's viewport size, connection speed, and other factors.

Illustration of a browser window with the images outside the viewport grouped together indicating they will only load by scrolling down

How to lazy load

The most common method to apply lazy loading to an image is to use the HTML5 attribute loading="lazy" on content that is likely to appear beyond the initial viewport. While programmatic methods of lazy-loading images are possible, the techniques involved are beyond the scope of this article.

<img src="photo.jpg" loading="lazy">

Images that are visible in the initial viewport paint should not be set to lazy. If the attribute has been applied programmatically, it can overwritten to the default behavior with loading="eager".

So what's the problem?

The issue with lazy-loaded elements with no placeholder values is something called cumulative layout shifting; the movement or shifting of the interface after its first paint.

Understanding layout shifting

When an image does not declare its size and is lazily loaded and, the space it would occupy is not reserved or blocked on the document's paint. Since there is no image to reserve space for, the browser simply does not allocate any. As the document loads in and images are processed, the layout shifts to accommodate the additional height of the images.

Other elements such as custom fonts, JavaScript and CSS processing, or dynamically-loaded content can cause layout shifting as well.

The following illustrates how an image eventually pushes content down as the it loads in, causing a layout shift.

Illustration of two layouts side by side. The first displays an image that has yet to be loaded and takes up no space, the second shows a loaded image taking up much more room on the page

The impact on anchors

The extent of layout shifts can range from barely noticeable to considerable. The problem is particularly apparent when activating a link to content situated further beyond the visible area. As the window scrolls and images are loaded dynamically, the link's destination gets displaced, which can direct the user to the wrong location.

Fixing layout-shifting images

The simplest way to fix the layout shift cause by lazy-loaded images is to declare an initial height and width. Doing so reserves a preset amount of space to block.

<img src="photo.jpg" loading="lazy" height="100" width="600">

Height and width can also be declared with CSS.

<img src="photo.jpg" loading="lazy" style="height: 100px; width: 600px;">

Other resources

Aspect Ratio Boxes

Chris Coyier | CSS-Tricks

Cumulative Layout Shift (CLS)

Philip Walton, Milica Mihajlija | web.dev