Optimising Your Images Using srcset

Content:

When you’re adding images to your website, you’ll want to ensure they’re of a good size and quality.

However, an image sized for a desktop will be unnecessarily detailed for displaying on a phone, which has a much smaller screen.

While the browser will scale the image to fit, loading large images will involve the transfer of a large amount of data – only to throw some of it away.

Ensuring your site serves an appropriately sized image is a great way to boost performance, without impacting the appearance of your site.

So, how can you serve one image, which is right for such a broad range of devices? Fortunately, it’s easy, using a feature called srcset.

Introducing srcset

srcset is an attribute, that can be added to your img tag.

In it, you can provide a set of images, of different sizes. The browser can then choose the most appropriate of the images, based on the current display width.

The structure of an img tag, using an srcset, is as follows:

<img 
    src="image.jpg"
    srcset="
        image-1.jpg size
        image-2.jpg size
        image-3.jpg size"
/>

The browser uses the size following each file name when deciding which one to use. Should none of the srcset sizes be appropriate, the image used in the src tag is used instead.

There are two different ways of defining a size, which work slightly differently.

Scaling Factor

The simpler of the two sizing methods relies on a scaling factor.

Since the release of the iPhone 4 with its ‘Retina display’, devices (mobiles in particular) use much higher pixel densities than standard displays. With the shift towards 4k displays for PCs, higher pixel densities are likely to impact PCs and laptops going forward.

To make up for the smaller physical pixels on the display, such devices will scale their UI, using a scaling factor relevant to the pixel density of the device.

For example, a display double the standard pixel density, will use a scaling factor of 2. This means a single 1×1 pixel in software uses a 2×2 block of physical pixels on the device.

Using scaling factors with srcset, the browser checks the scaling factor used by the device, then chooses the image file to match. Values use the unit x.

<img 
    src="dog-small.jpg"
    alt="Photo of a dog"
    srcset="
        dog-full.jpg 4x
        dog-large.jpg 3x
        dog-med.jpg 2x"
/>

It’s important to ensure that each image is a scaled resolution of the original, to ensure it displays as expected.

2000x1000px.jpg 4x
1500x750px.jpg 3x
1000x500px.jpg 2x
500x250px.jpg 1x

This method is best suited for images that take a fixed size on your page, defined using CSS. If you know your image is constrained to 500px, for example, the only reason to go for a larger size is down to pixel density.

It’s by far the easier of the two to implement, so can be a great way to get started while you’re getting familiar with srcset.

Pixel Sizing

When using pixel sizing, the size following a file name should be the width of the image.

<img 
    src="dog-small.jpg"
    alt="Photo of a dog"
    srcset="
        dog-full.jpg 1920w
        dog-large.jpg 1440w
        dog-med.jpg 960w"
/>

Note that the unit used here is w, rather than px.

This gives greater flexibility, particularly if your site is responsive.

For sizes using the full width of the viewport, this is all you need to add. In other cases, however, there’s one more attribute that needs to be added.

<img 
    src="dog-small.jpg"
    alt="Photo of a dog"
    srcset="
        dog-full.jpg 1920w
        dog-large.jpg 1440w
        dog-med.jpg 960w"
    sizes="70vw"
/>

The sizes tag sets the value the browser uses when choosing an image. With this missing, the browser uses 100vw by default – which is why it can be excluded when your image is as wide as the viewport.

In the example above, our sizes attribute is set to 70% of the viewport width. For a viewport 1920px wide, this means the browser will use 1344px.

At least, it does if the device pixel density is 1. Scaling adds extra complexity, as the browser will correct the value to use the number of physical pixels, rather than the scaled software pixels.

For a 3x scaled device, our 1920px viewport and 70vw sizing attribute will give:

1920 * 0.7 * 3 = 4032px

It’s vital to understand the roll pixel density plays when the browser selects an image, as a device with a high density display will seemingly choose a larger than necessary image.

The sizes attribute accepts CSS media queries, making it ideal for response areas of your site.

sizes="(min-width: 960px) 25vw,
    100vw"

This sizes query will cause the browser to use 25% of the viewport width as a target size on larger screens, and full width on small screens.

sizes="(min-width: 960px) calc(100vw - 17rem),
    100vw"

You can use the CSS function calc() to compute sizes for more dynamic sites.

It can be tricky to get the sizes spot on if your site is complex. Rather than using complicated calc() calls, it’s recommended to find a more simple value that close enough to work in most cases.

Is There Any Point?

Assuming pixel densities haven’t totally fried your brain, you might be asking…

If a high res phone downloads a large image anyway, what’s the point?

Honestly, that’s a great question. You’d think mobile devices would be the prime target for a size-reduced image, owing to the smaller physical display and mobile data connection. In reality, your PC will probably download a lower quality image than your phone.

One thing to consider is that older devices, stuck on slow 3G connections, are far less likely to have high resolution displays – in which case, they will go for a smaller image.

The other is the power of the sizes attribute. When using the more complex sizing method, you can use your own CSS media queries to apply specific rules.