This post is over a year old, its content may be outdated.

Matt Wilcox

Web Development

Tutorials Oct 31st 2014

Keeping srcset and sizes under control

My strategy to ensure HTML's new responsive image attributes don't grow out of control when you use them.

When we're dealing with responsive images <picture> is the newness everyone is talking about, but most of the time we don't need to use it, instead we can make use of srcset and sizes, which are two new attributes that belong to the venerable <img /> tag. For more background on that try Opera's fantastic post 'Responsive Images: Use Cases and Documented Code Snippets to Get You Started'.

This post is a tid-bit on how I manage authoring the contents of the srcset and sizes attributes to avoid insanity. When making use of srcset it's easy to end up with a huge list of potential source files; two or three times the number of break points in fact, so if you've got five breakpoints and want to support 1x, 2x, and 3x DPI you can end up with 15 sources. That's not really ideal.

My process

The important step is consolidating the various sizes into a smaller group of acceptable compromises.

Here's a quick overview, code examples follow later:

  • Don't add those two attributes to an <img /> until the CSS for the page is done.
  • Have the window at maximum width and Inspect the image; view the 'Box Model' to see the rendered CSS-pixel dimensions.
  • Add a 'sizes' attribute to match those values at that breakpoint.
  • Shrink the window to the next breakpoint, add a sizes value following the previous one, and repeat until all breakpoints are done.
  • Add srcset attributes that match those sizes values (I work bottom-up for this).
  • Multiply all those sizes values those by your pixel density factors and add matching values to the srcset list (I do this in size order).
  • Remove all the srcset values that seem too close together to be of real benefit.
  • Adjust the src attribute to point to a sensible sized fallback.

The end result is a selection of sources that's manageable and practical without matching every possible combination exactly.

It's also important to work top-down for this if you're using min-width as your query. Unlike our usual experience of the cascade, where the last-matched rule is the one applied, with these it's the first-matched rule that's applied and anything after is ignored. This is an optimisation done for browser speed, and it's one I think is … a poor decision … (It's bad for authors because it's backward to expectation, and I can't imagine that the parser's speed benefit would be greatly hampered by going the more conventional cascade route. I digress.).

Here's some example code:

First pass

Just an image that's being sized in the CSS.

<img src="/images/placeholder.jpg" alt="" />

Second pass

Putting in the sizes attribute to allow the browser to know the sizes the image will be rendered at which breakpoints, prior to loading any CSS.

<img src="/images/placeholder.jpg"
      alt=""
      sizes="(min-width:1420px) 610px,
             (min-width:1320px) 500px,
             (min-width:1000px) 430px,
             (min-width:620px)  580px,
             280px" />

Third pass

Add in the matching srcset to cover those sizes at 1x DPI (for sanity, I re-order the srcset to be in pixel size rather than breakpoint size).

<img src="/images/placeholder.jpg"
      alt=""
      sizes="(min-width:1420px) 610px,
             (min-width:1320px) 500px,
             (min-width:1000px) 430px,
             (min-width:620px)  580px,
             280px"
      srcset="/images/1-280.jpg 280w,
              /images/1-430.jpg 430w,
              /images/1-500.jpg 500w,
              /images/1-580.jpg 580w,
              /images/1-610.jpg 610w" />

Fourth pass

Add in the 2x values for each of the existing srcset values (and again, I re-order into ascending sizes if needed)

<img src="/images/placeholder.jpg"
      alt=""
      sizes="(min-width:1420px) 610px,
             (min-width:1320px) 500px,
             (min-width:1000px) 430px,
             (min-width:620px)  580px,
             280px"
      srcset="/images/1-280.jpg 280w,
              /images/1-430.jpg 430w,
              /images/1-500.jpg 500w,
              /images/1-560.jpg 560w,
              /images/1-580.jpg 580w,
              /images/1-610.jpg 610w,
              /images/1-860.jpg 860w,
              /images/1-1000.jpg 1000w,
              /images/1-1220.jpg 1220w" />

Final pass

Remove srcset values that seem too close to be of real use. Replace the src value with a decent fallback from the srcset list.

<img src="/images/1-610.jpg.jpg"
      alt=""
      sizes="(min-width:1420px) 610px,
             (min-width:1320px) 500px,
             (min-width:1000px) 430px,
             (min-width:620px)  580px,
             280px"
      srcset="/images/1-280.jpg 280w,
              /images/1-430.jpg 430w,
              /images/1-610.jpg 610w,
              /images/1-1000.jpg 1000w,
              /images/1-1220.jpg 1220w" />

It's a time consuming process, but it's one that will speed up your visitor's browsing.