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 thesrcset
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.