As I mentioned in my post about Gemini, mine is a lightweight website for the most part; it’s built with a static site generator, I don’t use any heavy Javascript includes, and there are certainly no ads or trackers. The main exception I mentioned then was images: these were, by far, the major thing blowing out the filesizes (and loading times) of my pages and I knew there were improvements I could make to how I dealt with them. This is a post about some of the tricks I’ve learned, working on this over the last few days.

Lazy loading

Most of the things I’ll be talking about can’t really be done (or not so easily) on – they require a bit more control over how things are processed on the back end. This one, however, can be done. The principle of lazy loading is a simple one: rather than your browser loading all a webpage’s images at once, it should load them as they’re needed: when they’re currently on screen, or when you’re about to scroll down so they will be on the screen. If your blog’s front page has a long list of posts with relatively high-filesize images on it (like, ahem, mine), introducing this is a great way to save your visitors from loading megabytes of content if they never scroll that far down the page.

Until recently you had to use Javascript to implement lazy loading, and this is still the most flexible way to do it – lazysizes(external link) is one oft-used script. But most modern browsers (not Safari, alas) now recognise and will make use of a loading="lazy" HTML attribute to postpone loading certain images until needed. This is ludicrously easy to put into practice – every img tag you include in a post, just add that attribute to it, like you would alt text! This “complete guide” to lazy loading images(external link) has more information (including on Javascript options, if you scroll up) but it’s basically that simple.

One piece of advice you will see online is that the loading="lazy" attribute should not be applied to images that will appear at the top of the page (in the initial viewport). The thing with that is, there’s no real penalty to adding the attribute to an early-page image (the browser just ignores it and loads it anyway), and between pagination and single-post pages and so on, it would be totally unwieldy to try adding the attribute only to images that are at the bottoms of pages. My theory is: add it to everything I post on, and any milliseconds of delay will be made up for by the images that are never needlessly loaded at all πŸ˜‰

Responsive images

So, this page is a thorough guide to how responsive images work(external link). The idea behind them is also quite simple: your visitors might be looking at your site on all kinds of screen sizes, and to give them the best experience, you should try to serve them images that are roughly the size that will actually be displayed – not bigger (because then you’re wasting their bandwidth) and not smaller (so it looks crisp). So, you might have a single image in an array of different sizes, present that information to the browser, and the browser will load the most appropriate one for its current screen size at the time of viewing. Again, you don’t need any kind of sophisticated scripting for this – you can do it through regular HTML, specifically through the srcset attribute – check that link for an explanation.

Technically you could do this in… but you’d have to upload multiple copies of every image you want to post. So, I’ve focused my energy on implementing this change to my static site. Laura Kalbag’s post on processing responsive images in Hugo(external link) was very helpful for this. Basically I’ve declared images as “page resources” for my posts (book reviews, recipes, etc.), and then rather than calling that page resource directly in my template, I can resize it (multiple times!) and then call each of the resized images and pop the URLs in a srcset. Especially on pages with lots of images, this makes a huge impact. For example, each page of my book reviews(external link) had 20 different images on it, with a total filesize of over 900kB – not the worst ever, but it doesn’t even need to be that high! Now I’ve refactored all my reviews to make use of page resources, each page is now more like 400kB when viewed on a retina display – and 200kB on a regular display without pixel scaling. The best part is, I do not need to do any manual image-resizing myself – I can just chuck the full-size image in a folder with the post and Hugo does everything for me. It’s great. 😊

The aspect-ratio attribute

This one follows on from “lazy loading”, but it goes at the end of this post because it’s the thing I’ve learned most recently. Basically: if content hasn’t loaded and you scroll down the page, you might find elements on the page “jumping” about as earlier elements (like images) load and push the later ones out of place. To prevent this, you could specify a width and height and then the page will “reserve” that much space for the image before it actually loads and there’ll be no jumping about. But what if you don’t know the image’s size in advance?! My own layout, for example, has a main column spanning 90% the width of the viewport to a maximum of 800px. I can specify an image to take up 100% of the column, but then what do I put for the height? I can’t say what the height should be unless I know the width of the column – which I don’t.

The good news is that a new CSS attribute is coming to my rescue – aspect-ratio. Here’s a blog post about that(external link), but fundamentally it comes down to: if I know an image is to be displayed at 100% of the column’s width, and I know its aspect ratio (like 4:3, 1:1 or 4:5), I can define both those things and the browser can use them to set aside the correct amount of space when loading the page. Et voilΓ , no more page-jumping!

The sad news is that this attribute is not yet supported in the current stable versions of major browsers(external link) (except Chrome for Android). However, it won’t break anything to start using it (browsers that don’t understand it will just ignore it), and once it is introduced, using it will help improve the experience of using your site in those times when things are still loading.


If you have a personal or a hobby site like mine, it’s pretty likely that images will be (by far) the biggest thing blowing out your file sizes and thus, your load times. This could get especially annoying for visitors with slow or unreliable internet connections, or strict data limits. Obviously doing an initial resize of your images (and not just uploading things at 4,000 by 3,000 pixels πŸ˜‰) helps, but there’s loads more you can do. Lazy loading on long pages – so people don’t have to load content they never see – is a big help and relatively easy, while with a bit more effort (or some clever Hugo templating) responsive images offer massive savings. For me, while I know my humble site is far from the worst offender on the web (how about those sites that never finish loading because they have scripts constantly doing shit in the background?!), I do feel proud when I see my webpages getting leaner and faster. To me, that kind of efficiency is how the web should be. Sharing my thoughts, my photos, and stuff I think is cool is great – but even better to make sure I’m providing a great viewer experience as I do so 😊