Avoid downloading hidden images on mobiles

In constant pursuit of a faster loading website, I realised that a large chunk of the initial download was taken up by loading a single SVG image.

If you're viewing this article on a PC/laptop/tablet, you'll see the image above the title on the left. However, if you're viewing this article on a mobile, the image isn't visible.

Like most responsive websites, certain elements aren't necessary in a smaller window, and they're simply hidden to make room for more important content.

But... that image is still downloaded, even if CSS has hidden it:

Image downloaded

Using the Picture element

Fortunately, we can use the picture element to specify when the image is downloaded. Here is what I had before:

<img alt="Author image" class="author__image" src="~/assets/images/logo.svg" width="180" height="130" />

Now, let's wrap it with the picture element:

<picture>
	<source srcset="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" media="(max-width: 60em)"> 
	<img alt="Author image" class="author__image" src="~/assets/images/logo.svg" width="180" height="130" />
</picture>

What does this do?

Let's step through this bit by bit:

  • The picture element zero or more source elements, along with a single img element.
  • Each source element has a srcset attribute, for referencing a URL to an image (or image data), and a media attribute specifying when that source should be used instead of the img.
  • Most importantly, if a source element is used instead, then only that source will be downloaded. If the media query is no longer true (i.e., the user resizes the window), then either another source or the default img will be downloaded.

In the example above, the srcset contains the following data:

data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=

This is a 1x1 pixel transparent gif, encoded in Base64. In this particular use case, I never want an image to show if the screen width is less than 60em wide, so using the smallest possible file was the best solution.

And now, when I reload the page, the image is no longer loaded, saving me a whopping 6.2kb. It all adds up!