How to lazy load images in Hugo

By

Learn how to lazy load images in Hugo by overriding the image render hook so the generated img tags get loading=lazy, cutting bandwidth on long pages.

~~~

To lazy load images in Hugo, you override the image render hook so every image generated from Markdown gets the loading="lazy" attribute. One template file, and the whole site is covered.

Let me explain why I needed this.

When I launched the new home for my ebooks at The Valley of Code I didn’t think about my hosting bill, and the impact of loading lots of images for the clients as well.

Since each page is very long (no navigation, that’s the point of them being books rather than articles), one could even be 10MB.

So I decided to fix this problem by lazy loading them, in other words the browser only loads the image when the user scrolls to that image.

It’s a tradeoff, but I’m pretty sure 99% of people that open a page will never even scroll to that image right away.

Problem was.. I had no control over the markup! All the content was in Markdown.

But I found out Hugo allows us to override how images are rendered.

How the image render hook works

Hugo has render hooks: template files that control how Markdown elements are turned into HTML. There’s one for links, one for headings, one for code blocks, and one for images.

When Hugo finds an image in your Markdown content, like this:

![The JavaScript Handbook cover](/images/covers/javascript-handbook.png)

…it looks for an image render hook template. If it finds one, it uses it instead of the default <img> output.

Create the file layouts/_default/_markup/render-image.html in your theme with this content:

<img src="{{ .Destination | safeURL }}" alt="{{ .Text }}" loading="lazy" />

.Destination is the image URL, and .Text is the alt text you wrote in the Markdown. The template adds loading="lazy" to every image, in one single place.

Rebuild the site and check the output. The Markdown image above now renders as:

<img src="/images/covers/javascript-handbook.png" alt="The JavaScript Handbook cover" loading="lazy" />

loading="lazy" is a native browser feature. No JavaScript library needed. All modern browsers support it, and a browser that doesn’t recognize the attribute just ignores it and loads the image right away. Nothing breaks.

One thing to watch out for

Be careful with images at the top of the page.

If the first image a visitor sees is lazy loaded, the browser can delay fetching it, and it shows up late. That hurts the perceived speed of the page, and your Largest Contentful Paint score with it.

In my case that was fine, because these pages start with text. If your pages open with a big hero image, keep that one eager and lazy load the rest.

Also notice the hook only applies to images written in Markdown syntax. If you have raw <img> tags inside your content files, Hugo leaves them untouched. You need to add loading="lazy" to those by hand.

Tagged: Hugo · All topics
~~~

Related posts about hugo: