Preloading Images in a Responsive, WebP World
Tags: html, performance
Published: 2021-07-29 21:12:09

It’s time for another Google Core Web Vitals themed TIL. This one concerns image loading. Specifically, huge, above the fold image preloading.

The site I work on uses a lot of super wide to full width hero images. We’d done some previous optimizations around serving images in WebP format (**Serve images in modern formats**) and using `picture` and `srcset` for responsive images (**Properly size images**). I won’t go into details since those topics already have a ton of tutorials that explain things better than I ever could. In fact, Smashing Magazine alone has you covered with [Using WebP Image Format Today](https://www.smashingmagazine.com/2015/10/webp-images-and-performance/) and [Responsive Images Done Right: A Guide To picture And srcset](https://www.smashingmagazine.com/2014/05/responsive-images-done-right-guide-picture-srcset/).

**Preload critical assets to improve loading speed.**

The one downside to our earlier work? It made things a little more confusing when we started looking into preloading images.

Preloading assets that aren’t actually used isn’t particularly helpful (Chrome will even warn you if you do it!). If you’re serving a WebP image but preloading the fallback or preloading a mobile image on a desktop browser, you aren’t getting any benefits out of it.

Let’s say you have a `picture` block that selects an image based on browser support, screen resolution, and breakpoint:

```html
<picture>
  <source srcset="large-image.webp, large-image-2x.webp 2x" media="(min-width: 768px)" type="image/webp" />
  <source srcset="large-image.jpg, large-image-2x.jpg 2x" media="(min-width: 768px)" />
  <source srcset="small-image.webp, small-image-2x.webp 2x" type="image/webp" />
  <img src="fallback-image.jpg" srcset="small-image.jpg, small-image-2x.jpg 2x" />
</picture>
```

The first question is how to handle different image formats. Looking at the Can I use entries for [Webp image formats](https://caniuse.com/webp) and [preload](https://caniuse.com/link-rel-preload), it seems pretty unlikely for a browser to support preloading but not WebP images. And according to a quick aside in this Addy Osmani [article](https://addyosmani.com/blog/preload-hero-images/) on hero images, you can use the `type="image/webp"` attribute with a `link` tag to specify that you want to preload a WebP image.

Next, we need to deal with screen sizes and resolutions. In addition to `type`, the `link` tag supports `media` and `imagesrcset` attributes which should look very similar to the `media` and `srcset` attributes on our `source` and `img` tags. The main difference is that you have to be more explicit with your breakpoints since the browser won't be choosing the best image itself.

Putting that all together, you would add this code to your `head` tag to preload the images from the example above:

```html
<link rel="preload" as="image" href="large-image.webp" media="(min-width: 768px)" imagesrcset="large-image.webp, large-image-2x.webp 2x" type="image/webp" />
<link rel="preload" as="image" href="small-image.webp" media="(max-width: 767px)" imagesrcset="small-image.webp, small-image-2x.webp 2x" type="image/webp" />
```

If you prefer an example with real images, check out [this Pen](https://codepen.io/laurenashpole/pen/KKmoqeO) on Codepen. Just click on Settings and HTML to view the preloading the code.