Understanding HTML5 srcset

Published on: February 8, 2015

Every since responsive design became a thing people worried about the sizing of their images. Why would you serve an image that's 1800px wide to a device that is only 320px wide? That's a very sensible question to ask when you're dealing with responsive design. If you consider that this 320px wide device might very well be a mobile device that's using a 3g connection this question makes even more sense.

Working towards a solution

I think it was a few years back when I saw people debating the problem of responsive images. How would the syntax look? How will it be compatible with current browsers? HTML5 isn't supposed to break backward compatibility. I've seen a proposal for a element come by. That looked promising. But eventually something else come along and it’s called the srcset.

How it works

The srcset is an attribute that takes a list of images that a browser can choose from. By using the srcset you are trusting the browser to make smart decisions about what image is shown. If you want to have a crop out on small screens and then a different version on larger screens you might be in for trouble. Browsers are entirely free in their interpretations of the srcset attribute. They (should) try to be sensible, but Chrome 40 caches your images, so making the viewport smaller won't trigger a reload on the image. Why? Well, why would it. The browser assumes that a higher resolution version is 'better' and it won't waste an extra URLRequest on fetching your lesser quality image.

An example of using srcset:

<img src="http://placehold.it/100/100"
         http://placehold.it/320/320 320w,
         http://placehold.it/640/320 640w,
         http://placehold.it/960/320 960w">

The list we define uses this syntax:

<image_src> <image_width(in pixels)>

We could also define a pixel density:

<image_src> <pixel_density(2x, 3x etc.)>

But I want to have some control

Understandable, while this feature is somewhat of a block box, it isn't all black magic that goes on as Chris Coyier illustrates in his blogpost: You're just changing resolutions. The bottom line of what he illustrates is that a browser uses simple math to determine the best image for the current case. What the browser does is devide the image width by the viewport width and then checks how it matches the current pixel density.

Example from Chris' blog:

320/320 = 1
640/320 = 2
960/320 = 3

Imagine using a browser that has a 320px viewport. The images we are offering are 320, 640 and 960 wide. The browser does the math and decides that the 320w image is the best one since we are using a 1x pixel density device.

Now imagine using a retina device in this same case. The browser will now use the 640w image. Why? Well, a retina device has a 2x pixel density. So the 320 image is too small. It needs a bigger image.

More control please!

The browser always uses the full browser width to do the math now. But what if we needed to display images at 33% of the viewport on large screens, 50% on medium screens and 100% on small screens?

This is a question I really struggled with for a bit because here's where things get magical. But luckily we got a great mental model to work with because of Chris Coyier's examples. So, let's use the same html snippet we had before but we add the rules I just specified by using the sizes attribute.

<img src="http://placehold.it/100/100"
         http://placehold.it/320/320 320w,
         http://placehold.it/640/320 640w,
         http://placehold.it/960/320 960w"
         (min-width: 768px) 50vw 100vw,
         (min-width: 1200px) 33vw">

I've used some arbitrary values for the definition of what is small, medium and large. The first line should be explained, it says that we intend to display images at 50vw on a viewport that's 768px wide. If it's smaller we use 100vw. We don't need that "if it's smaller" part on the second size because we already defined a rule for that.

Okay, so now let's do the math again:

(320*1)/320 = 1           //viewport is smaller than 768px
(640*1)/320 = 2           //viewport is smaller than 768px
(960*0.5)/320 = 1,5     //viewport is smaller than 1200px

With this math we can see that viewports at 320px and 640px are actually pretty predictable. A viewport with 960px is a strange case. The browser will either pick the 320w image or the 640w image. I would expect the 640w image because 1.5 can be easily rounded to 2 but it's up to the browser to implement this.

Using the srcset

I feel like it's pretty save to go ahead and use the srcset right now. The fallback is good since it's just a regular tag with a source attribute set on it. However, do make sure that you sort off understand how a browser might interpret your srcset. It could save you many headaches and it will make you feel more confident about using it. if you want to know more about the srcset I strongly recommend reading You're just changing resolutions since it's a good description of how srcset works.

Questions, comments, notes, feedback, it's all welcome. You can find me on twitter for that.



Subscribe to my newsletter