ericportis.com

Keep ’em Separated

The words “MARKUP” and “LAYOUT” written on top of one another in red and cyan.

The problem

The picture spec is coming to Chrome stable in the next few weeks (keep an eye out for version 38!), and I couldn’t be more excited. Native responsive images are long overdue and the new features are terrific. But I want to write about my least favorite thing about them: sizes explicitly demands that we duplicate/distill layout information from CSS and put it right in our markup, violating two basic principles at once:

This duplication is necessary given current technical constraints. Any browser that wants to load images responsively needs to load one amongst many available sources depending, in part, on the image’s layout size. But we can’t be sure that browsers will know the layout size of an image by the time they begin loading it. They never have, and probably never will. The only way around this browser-needs-to-know-before-it-knows problem is to put the relevant layout info right there in the markup where the browser can see it as soon as it encounters the img. Thus, sizes.

Matt Wilcox wrote a thing warning developers about the worst practical effect of this: any time we change our layout, we risk having to change a bunch of sizes (and media) attributes, too.

Fragile markup that violates the separation of concerns is a real bummer. How can we mitigate that bummer now, and is there anything on the horizion that might help us eliminate it, going forward?

Automate the pain away

Automation lets us keep the markup we author by hand clean; a robot can read the relevant style information from somewhere else (ideally the CSS!) and use it to duplicitously dirty our content for us. One can imagine writing the following:

<img data-fullsize="fullsize.jpg" src="fallback.jpg" alt="¡Obama mambo!" />

And then through some server-side pre-processing magic:

  1. fullsize.jpg gets downsized into a number of smaller versions, which are automatically marked up in a srcset (easy).
  2. An algorithm distills the image’s variable layout width down to a sizes attribute that gets added to the img (hard).

Nothing like this exists yet. It should!

In the meantime it seems relatively trivial to still write our sizes by hand, but do so only once for each style of image. Robots can stick a centralized sizes value onto every image of a certain class at pre-processing time. We’d still be duplicating layout information, but only once – when the layout changes we’d find ourselves needing to change one line in a config.yml (or whatever), and not a hundred identical sizes.

Leave off sizes entirely

sizes lengths don’t have to be a precise representation of the width of the img; it’ll often be prudent to trade a little accuracy for big gains in simplicity.

The most extreme version of this trade: leaving sizes off entirely. Without it, the browser defaults to an implicit sizes value of 100vw, which, for important images that will probably be fairly large no matter the layout, isn’t a bad guess. Small, low-res viewports still get small images; big, hi-res viewports still get big ones. We avoid duplicating layout information and muddling our content and presentation.

But as the gap between the width of the img and the width of the viewport gets bigger, this tradeoff gets worse. An img without a sizes that only occupies 100px of a 1000px viewport presents the browser with an estimate of its size that’s off by an order of magnitude.

Going forward

Is there anything on the horizon that might help?

Resource priorities might. Resource priorities provide developers with a way to explicitly delay the loading of the image until long after its display width can be known. A smart browser might see that an image has a load-policy (or whatever) of when-needed (or whatever), and delay choosing a source until it actually knows the image’s exact layout size – no sizes estimate necessary. For images that aren’t likely to be visible from the get-go, this could be a great solution.

Long term, the best solution may be to split loading into two phases – browsers could load and display a low-resolution version of the image ASAP, and then enhance post-layout.

RICG hero-of-the-revolution Yoav Weiss sketched the outlines of such a thing a year ago. If his idea or something like it comes to fruition, users would see something quickly and never, ever load more or less data than they need. Developers would only have to deal with one source file per image, and would never need to duplicate any layout information in their markup. Everybody wins!

Someday, maybe.