Text content of all my 300+ blog posts is less than 2 MB in size containing the metadata. An image taken with mobile phone can be 5 MB.

No wonder that image optimization is critical to create a performant website. Here is how I do it in Hugo framework on my website.

Native image processing in Hugo

My blog has around 1000 images. That does not include the size versions, only the originals.

After a Hugo build is finished there are around 2500 processed images considering different size versions. It is pretty impressive that this takes only around an minute on my laptop.

On server it takes longer probably because of less performant CPU.

Downscaling the original images

Some of my early traveling photos were huge in old Wordpress site. The biggest was 10 MB. I converted all to maximum of 1920 x 1080 pixels. Mostly to save storage space because I would downscale them in Hugo anyway. Even the old Wordpress site did not show the original pictures.

As a result the total storage size dropped from 263 MB to 183 MB for “original” images. That makes 44% reduction of pixels that were never showed to the user!

The max width of images shown to the site visitor is only 1140 px on my site. The exact pixels come from the typical grid size of UI component library Bootstrap .

I still want to store larger versions if:

  • Some day I need better resolution
  • Visitor wants to zoom in the original image

Hugo images in version control

Hugo generates the missing image size versions on each build.

If the images already exist in the resources/_gen/images cache folder the build time is significantly faster. In the beginning I did not include the images in Git version control. My build times were 6 minutes in Vercel.

After images were included in Git the build time dropped to 1 minute!

Responsive images in Hugo

Both the Wordpress and Hugo sites deliver(ed) the images at the minimum size based on visitor screen dimensions. Hugo was able to achieve this natively while Wordpress required a plugin.

Web page analysis tool Google Lighthouse suggests that images on web pages should have explicit width and height attributes. This can be tricky for static website and responsive images.

My solution was to set the dimensions to the largest dimensions like this:

    <style>
        img {
            max-width: 100%;
            height: auto;
        }
    </style>
    <img 
        sizes="
            (min-width: 1200px) 1140px,
            (min-width: 992px) 960px,
            (min-width: 768px) 720px,
            100vw"   
        srcset="
            img1140.jpg 1140w,
            img960.jpg 960w,
            img720.jpg 720w,
            img540.jpg 540w"
        src="img.jpg"
        width="1140"
        height="641"
        loading="lazy"
        alt="Text if not visible"
    />

I can see from browser developer tools that images are rescaling when I change the screen size. But sometimes the breakpoint does seems to be different than inteded. Some blog posts indicate that there would be a virtual screen size affecting to this behavior.

I have also wondered wether the browser could take a bit too large image just in case.

Well, my solution is close enough.

I also warmly recommend the lazy attribute to load images only when they are showed to the visitor. In this case it is a known fact the browsers load the images slightly before the photo becomes visible.

Hugo and webp images

The webp images should have better compression rate compared to jpg or png. This leads to faster page loads and better user experience.

The extended version of Hugo would provide ability to process also webp format. Some day I will start using the extended version. But before that I probably bulk convert the old images to webp by using a Python script.