When do you have to repeat redundant sizes attributes within a <picture>?
TL;DR
Almost always, but that might be changing.
Okay, so—
Let’s say you’ve got a <picture>
element that includes multiple candidate sources. If you’re doing art direction, those sources are probably each going to be laid out differently. This means they’ll each need their own sizes
attribute.
<picture>
<!-- landscape image over text -->
<source
media="(min-width: 600px)"
srcset="landscape-lg.jpg 1920w, landscape-sm.jpg 960w"
sizes="(max-width: 960px) 960px, 90vw"
>
<!-- square crop next to text -->
<img
srcset="square-lg.jpg 480w, square-sm.jpg 240w"
sizes="25vw"
>
</picture>
This pattern was generalized into a universal requirement: any time an element (<img>
or <source>
) had a srcset
that included w
descriptors, it also needed its own sizes
.
But for media
-switching that isn’t related to layout changes (e.g., responding to prefers-contrast
), or for the type
-switching use case, this requirement just leads to repetition.
<picture>
<source
type="image/jxl"
srcset="lg.jxl 1000w, sm.jxl 500w"
sizes="(max-width: 960px) 768px, 80vw"
>
<img
srcset="lg.jpg 1000w, sm.jpg 500w"
sizes="(max-width: 960px) 768px, 80vw"
>
</picture>
When you’re using sizes=auto
, it doesn’t even make sense in the art direction case, because the browser is just going to figure the sizes
out on its own.
<picture>
<!-- landscape image over text -->
<source
media="(min-width: 600px)"
srcset="landscape-lg.jpg 1920w, landscape-sm.jpg 960w"
sizes="auto"
>
<!-- square crop next to text -->
<img
loading="lazy"
width="480"
height="480"
srcset="square-lg.jpg 480w, square-sm.jpg 240w"
sizes="auto"
>
</picture>
Thankfully, sizes=auto
has been special-cased! If the <img>
’s sizes
value is auto
, you don’t need to duplicate it across your <source>
s. The previous example works the same in Chrome with or without sizes
on the <source>
. Yay!
Unfortunately,sizes=auto
and its special-cased handling aren’t supported everywhere yet. So in this example:
<picture>
<source
type="image/avif"
srcset="large.avif 2000w, small.avif 1000w"
>
<img
loading="lazy"
width="2000"
height="2000"
srcset="large.jpg 2000w, small.jpg 1000w"
sizes="auto, 50vw"
>
</picture>
Safari and Firefox will always use the last-resort 100vw
fallback as the sizes
value, after selecting the <source type="image/avif">
. Even though we put a better fallback length in our <img sizes>
, just for them!
Boo! This caught me out recently, and so here I am, blogging about it.
I think two things should happen:
- Safari and Firefox should implement
sizes=auto
, post haste. - The spec should be updated so that the
<img>
’ssizes
is used as a fallback, if the selected<source>
doesn’t have asizes
of its own. This isn’t only useful in thesizes=auto
case, it’s also useful fortype
-switching, and in any other situation where thesizes
values within a<picture>
would otherwise repeat.
I’m not the first person to have that idea. Jake Archibald had it four years ago. After some discussion, a handful of relevant parties seemed to agree. Jake even started a PR. So… let’s do it!