Adding lazy loading for images in Hugo static site generator

📅 Posted 2020-05-13

I recently added lazy loading to images on my blog, just to see if I could get the overall page load time down. I’ve tried to make sure my site is already pretty fast, but I’d like to see what other bit of juice I can squeeze out of the lemon, especially for slower connections.

You could do this with a custom shortcode, but that’s not fun because any existing image tag in content won’t be rendered with the appropriate markup.

You could use Javascript for this as well, with bunch of functions and observer and what-not, but I’m trying to add lightness (and therefore speed) so I don’t really want to be adding JS. Plus I want it to work nicely for the noscript kiddies out there, too.

I am, of course, relying on a fairly bleeding edge feature of “loading” which is not supported by all browsers just yet. But that’s OK, it will become more widespread over time. No, I’m not going to polyfill this one.

I’m a fan of this quote:

Simplify, then add lightness

~ Colin Chapman, Lotus Philosophy

Step 1

Download and set up Hugo… but I’m assuming you’re already there!

Step 2

Customise the img tag using Hugo’s handy feature (since v0.62.0) known as “markdown render hooks".

Basically, this allows you to overwrite the built-in tag rendering for specific elements such as links and images. You could, for example, add rel=noopener onto all external links using this technique.

I’m going to add the “loading” attribute with a value of “lazy”. More info on this attribute is available here.

I created a file in /layouts/_default/_markup/render-image.html like this:

<p>
  <img loading="lazy" src="{{ .Destination | safeURL }}" alt="{{ .Text }}" {{ with .Title}} title="{{ . }}"{{ end }} />
</p>

Simple as that. All images which are inserted into markdown will automatically be lazy loaded in a supporting browser.

Step 3

Publish and we’re done here. What does it look like? Well it’s a bit rough in Firefox 76.0.1 because there is no appropriately sized ‘placeholder’ image so the text will get pushed around when the lazily loaded image comes down the network. Not too bad on a fast connection, but not the best user experience in the world.

What about adding lightness?

Here’s a before snapshot of my The Humble MiniDisc article, which is fairly image heavy:

Text, Page, Word, Number, Symbol, Menu

And now after applying the code above, sitting at the top of the article:

Text, Page, Menu, Clothing, Pillow, Cushion, Home Decor, Symbol, Number, White Board

And then now scrolling all the way past all the images:

Text, Page, Number, Symbol, Word, Menu

So I can definitely see it’s working and Firefox is loading the images when it think they are needed. But what about the speed? Not a huge impact there on a decent connection, so we’ll throttle down to “Good 3G” speeds and see if that makes a difference.

Before:

Word, Symbol, Number, Text, Trademark, Logo, Oars

After:

Text, Number, Symbol, Word, Logo, Trademark

Yep, definitely an improvement in page load time as well as bandwidth consumed.

So I give this a thumbs-up. Recommended. As always, thanks for Hugo for being the best damn static site generator out there.

Like this post? Subscribe to my RSS Feed RSS Feed Icon

Comments (0)

Add a comment