3 Easy Tips for Fast-Loading Website Images

Inspired by a web performance blog post on Builder.io, I looked into how I could easily improve loading times on Privacy-First Jobs and found a few quick wins I wanted to share. They all relate to images, which have the biggest impact on page-load speed, and they’re all super easy to implement.

1. Use WebP Images

Although WebP has been around for over decade, I’ve hesitated to use it because of concerns about browser support. Turns out I shouldn’t have waited so long, for two reasons.

  • WebP has 97% support among global web users.
  • It’s easy to add fallbacks for older browsers.

It’s also easy to create WebP images now, thanks to native support in software such as GIMP and Photoshop, and tools like the imagemin-webp package for NodeJS. I’ve also added an appendix below with a Python script to convert JPG images to WebP.

WebP for Inline Images

If you prepare both WebP and JPG/PNG versions of images, the <picture> element is the perfect vehicle for letting the browser decide whether to use WebP or not. Here’s how to use it:

  <source srcset="photo.webp" type="image/webp">
  <img src="photo.jpg" alt="photo">

The <picture> element also has 97% global support but that doesn’t really matter, because browsers that don’t support it will just ignore it and use the legacy JPG/PNG format. Progressive enhancement at its finest.

WebP for Background Images

Adding a fallback is not quite so easy for CSS background images so my preference is to simply have a block colour or CSS gradient* combined with a WebP image, so at least something is displayed to unsupported browsers.

body {
  background: #c0ffee url("background.webp");

Alternatively you could use something like Modernizr to detect browser support, as explained in this CSS Tricks article, but personally I prefer to avoid the extra JavaScript and just stick with the simplified fallback.

* Note that you should choose a background colour or gradient with a similar tone to your background image, so that text has enough contrast to still be readable if the image doesn’t display.

JPG and WebP Comparison

Slide the arrows to compare JPG (141KB) on the left with WebP (98KB) on the right.
Close-up comparison of a JPG image (141KB) and an identical WebP image (98KB). The WebP image has much fewer artefacts, despite having a smaller file size.

As you can see, not only is the file size of the WebP image 30% smaller, it also looks better with fewer artefacts.

2. Use Lazy Loading

In the olden days we used to copy and paste write JavaScript to achieve this and now it’s available natively to 93% of global users – what times we’re living in! To use it, add the lazy loading attribute to <img> elements and their images will be loaded when they come into view, i.e. when the user scrolls to see them if they’re below the fold.

  <img src="photo.jpg" alt="photo" loading="lazy">

The beautiful part of this is that unsupported browsers will simply ignore the attribute and load the images normally, so there’s really no downside to using this everywhere. Combine it with the WebP <picture> element code above for double the goodness!

3. Use Compression Tools

There are similar services out there, as well as native software like ImageOptim, but I love TinyPNG‘s speed, simplicity and aggressive optimisation. Simply load or drag your images onto the TinyPNG website and you can then download a lighter version of each one. I find it works best with PNGs as the quality of JPG and WebP images degrades a bit too much sometimes, but for all those favicon-type logos in your root directory that aren’t SVG, it’s perfect.

PNG Compression Example

Let’s see an example of its effectiveness with this Mastodon image. The original is 230KB. Run it through TinyPNG and it goes down to just 65KB. That’s a 72% reduction in file size, although admittedly unusually high in my experience – I usually get 20-30% reductions.

As far as I understand it, the bulk of the savings come from a reduction in the indexed colour range, which means any gradients become less smooth but generally imperceptible to the human eye, as you can see in the comparison and zoomed-in versions below.

Slide the arrows to compare the original 230KB image on the left with the 65KB image on the right.
A zoomed-in comparison of the original 230KB image on the left and the 65KB image on the right. There are a few artefacts in the optimised image  but good enough for most use cases.

For some people these tips are nothing special – none of the technology here is new anymore – but I’m surprised at how often I see uncompressed PNG images on the web, or JPGs instead of WebP (my own sites included). Hopefully this brings a little more awareness to web developers, and a better experience to web users.


Here’s a Python3 script for converting JPG images in multiple directories into WebP format with a quality of 80%:

import os
from PIL import Image # Ensure you have PIL (Pillow) installed first

root_directory = '.'

def convert_to_webp(image_path):
    img = Image.open(image_path)
    webp_path = image_path.rsplit('.', 1)[0] + '.webp'
    img.save(webp_path, 'WEBP', quality=80)

def process_directory(path):
    for entry in os.scandir(path):
        if entry.is_file() and entry.name.endswith('.jpg'):
        elif entry.is_dir():


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s