As of version 9.1, Drupal automatically lazy-loads images by default. This functionality adds a loading="lazy"
attribute when outputting an <img>
tag. When the browser sees this, it will not download the image until it enters the viewport. This can save your user (and your web host) gobs on bandwidth by not downloading images that will never be used.
However, lazy-loading will also delay the image, which is a problem if it’s located “above the fold” — meaning that the image is in the viewport when the page loads. This will negatively impact your user’s experience, as well as slow down the Largest Contentful Paint metric within Google’s Core Web Vitals.
Now you can control when and where to lazy load images
New to Drupal 9.4 is a UI that controls the lazy loading on an image per field basis. This enables granular control over which image or media field gets lazy-loaded.
To access this UI, navigate to the “Manage display” tab of your content type, and click the “gear” icon that corresponds to your image field. This will open the field format options for the image, and there you will find a new “Image loading” details element where you can set the lazy-loading value. There are two values, “lazy” — which tells the browser to lazy-load the image, and “eager” which tells the browser to download the image as normal. “Eager” is what the browser will do if the lazy
attribute is missing.
Best practices
Because Drupal injects the loading
attributes on the server, it can’t know if the image is rendered “above the fold”. This mean that we, as developers, need to make architectural decisions that will enable us to choose whether to lazy-load or not.
Drupal allows us to set the lazy-load options within an entity’s “view mode”, and we can choose when and where to render each view mode. With this knowledge in mind, you might choose to create a “hero” view mode that we know will be rendered above the fold. Or you may modify the default view mode, if you know the primary image will be rendered above the fold.
Drupal’s Views module also allows you to set whether to lazy-load or not!
This can be useful when using attachment views that render near the top of the page.
Even more granular control
If you need even more granular control, you can set the loading attribute when preprocessing the image field
function my_module_preprocess_image(&$variables) {
$variables['attributes']['loading'] = 'eager';
}
You can also modify it from within the image.html.twig
template (or its variation).
<img{{ attributes.setAttribute('loading', 'eager') }} />
If you want extra control in Views, you can use a module like Views Parity Row to change view modes based on which row is rendered. This will allow you to set the first x rows to have loading="eager"
and then leave the rest of the rows to default to lazy-loading.
Wrapping up
Support for lazy-loading images isn’t 100% there yet. Drupal doesn’t yet support lazy-loading of responsive images. In order to do so, the image needs to have its width
and height
attributes set so that there isn’t a content-shift on load. You can track this (and help out) at https://www.drupal.org/project/drupal/issues/3192234.
That being said, this new UI is a fantastic addition to Drupal core, which will enable developers to significantly speed up their sites, if they know when and how.
Hey you! Leave a comment!1
Seriously... I really like it when people let me know their thoughts and that they've read this.
Thanks Mike.
Lighthouse penalizes lazy loaded images that appear above the fold with the following error:
Largest Contentful Paint image was lazily loaded
Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint.
One study found that:
To fix this in Drupal 9 or 10 for a single above-the-fold image style, you can switch from lazy to eager loading try the following. My image style is called "hero".