Srcset, Part 2: The W descriptor and Sizes attribute

August 22, 2015

In part 1, I talked about how srcset can be used for device-pixel-density-based selections mainly for serving larger images to retina devices and smaller images to non-retina devices. This use case is great, but srcset goes a step further and allows you to query not just in the context of retina/non-retina, but also in the context of responsive design. The W3C refers to this as "viewport-based" selections.

The x descriptor is used for device-pixel-density-based selections and accounts for Retina, while the w descriptor, is used for viewport-based selections and accounts for respsonsive. This article hones in on the w descriptor. Here’s an example:

<img 
src="images/medium.png" 
srcset="images/big.png 1600w, images/medium.png 1000w, images/small.png 600w" 
sizes="(min-width: 1000px) 1600px, (min-width: 600px) 1000px, 600px" 
/>

First, the w descriptor works in tandem with the sizes attribute, which we’ll come back to in a bit. But before we get in to that, the srcset attribute has a ‘set’ of image paths listed separated by a comma. Also included next to each image path is something like “1600w”. This is simply telling the browser that the image’s witdth is 1600px. Why use “w” instead of “px”, I’m not quite sure and the specification really doesn’t go in to why. The “w” was confusing to me at first, but its very simple. Think of 1600w as 1600px. So just to be clear, you are simply telling the browser the size of the image. This way the browser knows this information without having to actually go fetch the image. That’s key, because the whole point of srcset is to make only one image request.

Sizes attribute

Now that we’ve got that cleared up, let’s tackle the sizes attribute. We’ve told the browser how wide our images are, now it’s time to tell the browser what the preferred render size of the images are. With “render size” being the display size in the browser. So looking at the same exact example from before listed again below, the sizes attribute specifies a few things.

<img 
src="images/medium.png" 
srcset="images/big.png 1600w, images/medium.png 1000w, images/small.png 600w" 
sizes="(min-width: 1000px) 1600px, (min-width: 600px) 1000px, 600px" 
/>

First is a media query inside of parenthesis followed by 1600px. So this is saying to the browser something like, “If the browser is wider than 1000px, I’d prefer you to display the image at 1600px wide. After the first comma there’s another media query followed by your preferred display size for that circumstance. “If the browser is wider than 600px, my preferred display size is 1000px. Lastly there is just 600px, which is what we specify as the optimal display size if none of the media queries are a match. In our case, if the browser width is less than 800px, our preferred image size is 800px.

What’s really going on here?

Everything we’ve done so far is really only providing hints and suggestions to the browser. Ultimately the browser now has the information it needs to only download the perfect image for the width of the browser/device. We’ve told it how wide the images are and where they are located via srcset attribute. We’ve also specified what images we’d like to use under various circumstances via the sizes attribute. The browser also knows the width of itself. Chrome on desktop knows that currently the browser window is sized to 853px wide. Safari on an iPhone 5 knows your phone is currently being held in portrait-mode which is 320px wide. So with all this information the browser can make an informed decision and with one single request can get the perfect image for the situation.

Let’s go through one hypothetical scenario. If we were viewing our example image on an iPhone 5 held in landscape orientation (horizontally), that would be 480px wide. That misses both media queries which are looking for a minimum width of 1000px and a minimum width of 600px respectively. Our iPhone5 at 480px wide is under that. So the browser knows that the preferred display size is 600px, which is the last value provided in the sizes attribute. The browser then goes to the srcset attribute, where it knows that there are 3 images and one of them is 600w, or 600px wide. So it’s going to go fetch and use that image only!

Of course this is all provided that the browser supports srcset. What happens when the browser doesn’t support the srcset attribute?

Fallback

Remember from part 1 that the traditional src attribute is still needed. It will be used as the fallback for browsers that don’t support the srcset attribute.

Other factors

In part 1, I went in to more detail about the “other factors” that are considered by the browser when determining what image is best for the situation. A browser’s zoom level, network bandwidth, and if on a data network, how much data is left in a user’s mobile data plan! I won’t really go in to these factors too much again, but at the time of this article only the browser width, pixel-density, and zoom-level are factored in to the equation. Data left in the data plan and network bandwidth haven’t quite appeared in browsers yet.

The hero image use case

The big full screen hero image at the top of your home page is a good use case for the x descriptor implementation of srcset. I’ve been there in the situation where I’ve got a big hero image or a hero carousel that needs ginormously large images for wide-screen desktop monitors. In a responsive design, just shrinking down that very large image using max-width: 100% isn’t too fair for users who are recieving the image-o-saurus on their smart phone. Why does a small screen need an image that is 1600px wide? The original “picturefill” by Scott Jehl was a huge help here before srcset came around. But that required javascript which may be slower than a solution that is native in the browser like srcset. Also, in certain browsers there may have been double-downloads with the aggressive image pre-fetching that was going on in certain browsers like Chrome. Some browsers were pre-fetching the images before the javascript executed resulting in multiple images getting downloaded.

Anyway, the srcset attribute allows you to specify multiple images for different widths. So in the context of Goldilocks, Papa bear sized browser windows and devices get a papa bear-sized image, Mama bear sized-devices get a mama-bear sized image, and baby bear sized browsers and devices get a baby bear-sized image. Everyone’s happy.

Simplifying it

Using media queries inside of html might give you the same feeling you get when using inline style attributes for CSS. This is a necessary evil because the HTML is the first thing the browser parses and therefore the browser needs the information in the sizes attribute in order to know which image to download. If this information was in the CSS, it could be too late. Also, in the example of a full-screen hero image, it can be argued that the media queries in my example above might be overkill. For the hero image use-case, we can leave out the media queries altogether in lieu of something like this:

<img 
src="images/medium.png" 
srcset="images/big.png 1600w, images/medium.png 1000w, images/small.png 600w" 
sizes="100vw" 
/>

The sizes attribute is saying something like, “I prefer the image to always be 100% of the viewport, or browser window”. Then the srcset attribute is saying, “here’s where my images are located and this is how wide they are: 1600px wide, 1000px wide, and 600px wide. Then the browser picks the best one based on your browser width.

Live Example

Remember, you have to be using a supporting browser to see the image you would expect. So if you’re reading this on your phone you may not be seeing the 600px wide image, because your phone’s browser may not support srcset yet. For best results use the latest version of Firefox.

See the Pen Srcset, Part 2: The “w” descriptor by Rich Finelli (@richfinelli) on CodePen.

Browser Support

Not so hot. Not nearly as good as it is for the x descriptor. The “partial support” from Safari for iOS 8 and desktop Safari, as well as IE Edge, in the caniuse.com browser support table refers to support for device-pixel-ratio-based selcetions (x descriptor) but not viewport-based selections (w descriptor). Bummer for now, but of course this feature is on its way.

Resources

Mastering CSS: Book by Rich Finelli
Mastering CSS, the Book! Flexbox, Layout, Animations, Responsive, Retina, and more!
Mastering CSS, 2nd Edition, video course by Rich Finelli
Mastering CSS, Second Edition: 47 videos on how to make websites like a boss! Flexbox, Animations, Responsive, Retina, and more!
Back to top