ericportis.com

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:

  1. Safari and Firefox should implement sizes=auto, post haste.
  2. The spec should be updated so that the <img>’s sizes is used as a fallback, if the selected <source> doesn’t have a sizes of its own. This isn’t only useful in the sizes=auto case, it’s also useful for type-switching, and in any other situation where the sizes 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!

Update!

Looks like Jake is working on the PR again. Yay!