The <pic> element

Here's a bit of a kitchen sink solution with ideas that floated around.

• I've used media queries for the art-directed use-cases, because:  
viewport size descriptors of srcset are confusing, limited (e.g. you can't  
have separate image only for print), and there must be an option to always  
predictably select image in conjunction with same `@media` in CSS (to  
adapt size of other page elements to the picture).
• Browser-controlled resolution adaptation is good, so I've kept `1x`/`2x`  
descriptors of `srcset` (covers performance/dpi, not art-directed cases)
• I've specified (hopefully intuitive) interaction between MQs and  
resolution selection to support more cases.
• Improved alternative text — allows structured fallback, avoids  
duplication.
• Minimized verbosity. `picture` → `pic`, `srcset` → `src`. 2x image can  
be embedded with the same number of characters as 1x `<img>`.
• Default resolution can be controlled with CSS `image-resolution`.
• Allowed both attribute microsyntax and nested `<source>`/`<img>`  
elements. The former for brevity in common cases, and the latter for  
extensibility, `width`/`height` attributes to avoid reflows and fallback  
for HMTL4 UAs without repetition.
• I could not figure out powerful and clean syntax for breakpoint  
macros/uri templates, so I've left that out. Hopefully it can be added  
later.


##The `<pic>` element in examples:

     <pic src="image.jpg 1x">alt text</pic>

Same as `<img src="image.jpg" alt="alt text">`. The `1x` means 1:1 scale  
of image to CSS pixels.


     <pic src="small.jpg (max-width:320px), medium.jpg (max-width:768px),  
large.jpg">alt text</pic>

Selects image to embed based on width of the viewport.


     <pic src="portrait.jpg (orientation:portrait), landscape.jpg">alt  
text</pic>

Selects image based on orientation of the device.


     <pic src="whitebg.jpg 2x print, blackbg.jpg 1x">alt text</pic>

Embeds high-res image with white background when the page is printed, and  
a regular-res black image otherwise.


     <pic src="image.jpg">alt text</pic>

Embeds image at 192dpi (default scaling is 2x, possible to override with  
CSS).
Same as `<pic src="image.jpg 2x">alt text</pic>` or
`<img src="100x100px" width="50" height="50" alt="alt text">`.


     <pic src="image1.jpg 1x, image2.jpg 2x">alt text</pic>

Embeds image at either 96dpi or 192dpi, depending on capabilities and  
preferences of the user agent (UA can pick any alternative).

Same as `<pic src="image2.jpg 2x, image1.jpg 1x">alt text</pic>` and `<pic  
src="image2.jpg, image1.jpg 1x">alt text</pic>`.



     <pic src="small.jpg 0.5x, medium.jpg 1x, large.jpg 2x"  
style="width:100%">alt text</pic>

Selects image based on display resolution/zoom, and optionally width of  
the container (if UA has layout information available when image is  
[pre]loaded).
Unlike version with `min`/`max-width` media query, UA is allowed to pick  
any image and dynamically change the image (e.g. prefer cached image or  
download low-res first, replace with high-res when network is idle).



##(optional?) extended syntax:

     <pic src="a (mq), b 3x">alt text</pic>

is same as:

     <pic>
       <source src="a" media="(mq)">
       <source src="b" resolution="3x"">
       alt text
     </pic>

(I'm not sure if `<source>` should allow microsyntax in `src` `<source  
src="b 3x">` instead of `resolution="3x"`)


The `<source>` element allows `width`/`height` to be specified for each  
alternative:

     <pic>
       <source src="large.jpg" media="(min-width:1024px)" width="1024"  
height"="300">
       <source src="medium.jpg" media="(min-width:768px)" width="768"  
height="200">
       <img src="small.jpg" width="320" height="100">
       alt text
     </pic>

An `<img>` element can be used in place of any `<source>`.  
`width`/`height` defines size to display selected image at, but does not  
take part in selection of alternatives.

The common syntax for use with JS polyfills is expected to be:

     <pic src="…"><noscript><img src="…" alt="…"></noscript></pic>

##In formal terms

The `<pic>` element requires closing tag. The content is interpreted as a  
fallback for UAs that don't support `<pic>` or don't display the image  
(fallback includes text in <img alt> inside <pic>).

The `src` attribute contains comma-separated list of alternative images:

     src="alternative, alternative, …"

and each alternative consists of space-separated:

     url [resolution] [media]

The `resolution` and `media` are optional. Resolution defaults to the  
value of CSS `image-resolution` property, and UA stylesheet should include:

     pic {image-resolution:2dppx}
     pic img {image-resolution:1dppx}

i.e. the default resolution is `2x` for `<pic>` and `1x` for `<img>`  
unless author overrides the defaults with CSS.

Media query defaults to `all`.

If there are commas or backslashes in the URL they must be escaped with  
`\`.

Alternatives can be specified using `<source>` and `<img>` elements in  
addition to `<pic src>` attribute. Alternatives from `<pic src>` are  
evaluated first.

The algorithm for finding these elements:

1. For each child element of `<pic>`
 1. if the child element is `<source>` or `<img>` include it as an  
alternative
 2. if the child element is `<noscript>` and scripting is disabled,  
include all `<source>` and `<img>` children of the `<noscript>` as  
alternatives

e.g.

     <pic>
        <source> <!-- yes -->
        <noscript><img></noscript> <!-- maybe -->
        <video><source></video> <!-- no -->
     </pic>


The `<source>` element has following attributes:

* `media` — same as `media` part in `<pic src>`
* `resolution` — same as `resolution` part in `<pic src>`
* `src` — single URL without escaping or microsyntax
* `width` and `height` — analogous to `<img width/height>` for each  
alternative image

The `<img>` element in `<pic>` is equivalent of `<source src="… 1x"  
media="all">`.

The resolution is interpreted as a property of the image. It describes  
ratio of image pixels to CSS pixels for image's intrinsic size, like the  
CSS `image-resolution` property.

It acts as a hint for image selection, but not as strictly as a media  
query. User-agent is free to use 2x images on 2x ("Retina") displays, but  
may opt not to if network speed/cost or memory limitations prohibit this.

The user-agent may also opt to use a 2x image on a regular 1x display if  
it the page is zoomed in, when printing, etc.

Authors are encouraged to always use resolution descriptors instead of  
`device-pixel-ratio` media query to allow UAs optimize selection of image  
resolution.

Matching of media queries in `<pic>` must be consistent with matching of  
`@media` in CSS and `matchMedia` JS API, i.e. UA is not allowed to ignore  
or fake values in media queries to pick different image alternative  
(unless it does it consistently for the whole page at the same time).

     <pic src="image.jpg (min-width:500px)"></pic>

In the above example no image is shown (equivalent of transparent image  
with intrinsic size 0x0) if the viewport is narrower than 500px.


Algorithm for selection of the alternative:

  1. For each alternative in order
 1. if media query does not match, ignore the alternative
 2. if the media query matches
  1. pick all alternatives with media query identical to the one that  
matched
  2. ignore all other alternatives
2. If there are no alternatives left, use transparent image with intrinsic  
size 0x0
3. Select any image among picked alternatives

This algorithm may be re-evaluated between any event loop runs.

For purpose of this algorithm media queries are "identical" if they parse  
to the same sequence of tokens, ignoring insignificant whitespace. The  
default/implied `all` values are identical to explicitly specified "`all`".

----

Generally the first alternative (in `src` left to right, nested  
`<source>`/`<img>` in source order) that has media query that matches wins.

If there's more than one alternative with an identical media query, UA can  
choose among them, e.g. select best fit resolution or file format.

Note that resolution is not part of media query.
`<pic src="img2 2x, img1 1x">` is same as `<pic src="img2 2x all, img1 1x  
all">`, and since both alternatives have implied media query `all` that  
matches, UA can choose among them.


     <pic src="imageA (min-width:500px),
               imageB 1x (min-width:300px),
               imageC (min-width:800px),
               imageD 2x (min-width: 300px)">

If `(min-width:500px)` matches, then imageA must be used regardless of  
screen density or UA preference (since it's first to match and there are  
no other alternatives with such media query).

If `(min-width:500px)` doesn't match, but `(min-width:300px)` matches,  
then UA may choose between imageB and imageD (both have the same query  
that matched).

imageC will never be used (because imageA will always match earlier and it  
has a different media query).


     <pic src="portraitHD.jpg 2x (orientation:portrait),
               portrait.jpg   1x (orientation:portrait),
               landscapeHD.jpg 2x,
               landscape.jpg   1x">alt text</pic>

UA can choose resolution of portrait or landscapa version of the image.  
Same as:

     <pic src="portraitHD.jpg (orientation:portrait), landscapeHD.jpg,
               portrait.jpg 1x (orientation:portrait), landscape.jpg  
1x">alt text</pic>


-- 
regards, Kornel Lesiński

Received on Friday, 1 June 2012 05:33:47 UTC