When native lazy loading started becoming part of WordPress, I saw it as a good opportunity to revisit how theme images were being output.
For years, lazy loading had often meant adding another JavaScript library or relying on a performance plugin. That approach worked, but it also meant another moving part. The browser-level loading attribute changed the conversation because images could declare loading behaviour directly in the markup.
Checking The Theme Markup First
The first thing I checked was not whether lazy loading existed. It was whether the theme was outputting images properly. An image without sensible dimensions, alt text or a clear role in the layout can still cause problems, even if it loads later. Lazy loading should not become a way of ignoring poor image markup.
For ordinary content images, WordPress could handle a lot of the work. For theme-controlled images, especially hero images and card thumbnails, I wanted to be more deliberate.
Letting Normal Images Lazy Load
For images further down a page, the default behaviour made sense. If a visitor never scrolls to the lower sections, there is no reason to load every image immediately. This was especially useful on image-heavy pages where the first screen only needed a small part of the total media.
A simple theme image might still be output in the normal way:
echo wp_get_attachment_image(
$image_id,
'large',
false,
[
'class' => 'card__image',
'alt' => get_post_meta($image_id, '_wp_attachment_image_alt', true),
]
);
The important part was making sure the image was created through WordPress functions where possible, because that gave WordPress a better chance of adding the right attributes and responsive sources.
Treating Hero Images Differently
Hero images needed more care. If the main image is visible immediately when the page loads, lazy loading it can work against the first impression. In those cases, I usually wanted the browser to treat the hero image as important rather than defer it.
That meant outputting the hero image with explicit attributes and avoiding lazy loading where the image was part of the initial viewport.
echo wp_get_attachment_image(
$hero_image_id,
'full',
false,
[
'class' => 'hero__image',
'loading' => 'eager',
'alt' => get_post_meta($hero_image_id, '_wp_attachment_image_alt', true),
]
);
What I Took From It
Native lazy loading made performance work less dependent on JavaScript, which I liked. It also made image decisions more visible. Instead of treating all images the same way, I started asking where the image appeared, whether it supported the first screen and whether deferring it helped or hurt the experience.
Retrospectively, that was the useful part. Lazy loading was not just a setting to switch on. It was a reminder that images have different jobs. Some images should wait. Some images need to arrive quickly. The theme should know the difference.