picture要素の関連仕様って今どうなってるんだっけ?を調べたメモ

<picture> どうなった

勤め先がモバイルに注力していたこともあり、レスポンシブもへったくれもない世界を生きてきた。そのせいで、その類の情報にかなり疎くなっていたので、現状を軽く調査してみた次第。

HTMLでの画像リソース読み込み分岐の必要性

CSS には Media Queries があるので、Viewport の width であったりデバイスのピクセル密度であったりを条件にして background プロパティの指定をすれば対応できる。

反面、<img> 要素と src 属性にはそのような仕組みがないため、Media Queries で可能な条件で同じようにやろうと思うと、JavaScript で DOMContentLoaded のあとに"頑張って"操作するか、バックエンドで UserAgent に応じて"賢く"返す仕組みを用意しなければならない。

WebP のような画像形式にせよ、解像度レパートリーにせよ「最適」を突き詰めたとき、画像リソースの配信は複雑化と断片化が進む一方なのが現状だ。それを解決するのが <picture> 関連仕様ということになる。

現在の仕様

だいぶ前に <picture> 要素の関連仕様の話がではじめたころはまとまってない印象だったが、少なくとも制作者側にとっての仕様(インターフェース)は固まりつつある様子。

<picture> 関連仕様ということでまとめているが、後述するように <img>srcsetsizes といった新しい属性を指定できるようになり仕様面で強化されている。

HTML 5.1 Nightly に入ったっぽい

ずっとWHATWGのほうで更新されていた印象だったが、W3Cの HTML 5.1 Nightly のほうにもThe picture elementが追加されていた。

今回はWHATWGのHTML Standard - The Picture elementからサンプルを引用しつつ、この記事を書いている時点での仕様を紹介する。

要素は <picture> と <source>

<picture> は、0または1以上の <source> を内包し、そのあとに1つの <img> を持つ。次の例では、<source>media を条件として適合すれば srcset の値が <img>src として扱われる。

<picture>
  <source media="(min-width: 45em)" srcset="large.jpg">
  <source media="(min-width: 32em)" srcset="med.jpg">
  <img src="small.jpg" alt="The president giving an award.">
</picture>

<picture> 自体は <source><img> を結びつけるラッパー要素のような位置づけだ。<video> のことを思い出すと近いイメージで理解できるだろう。

属性は srcset と sizes と media

<picture> 関連要素は、それぞれ次のような属性をもつことができる。

  • <picture> : 特になし
  • <source> : mediasizessrcsettype
  • <img> : srcsizessrcsetalt

そしてこれらの属性の掛け合わせが鬼のように複雑だ。条件を指定したら画像とHTMLを書き出してくれるPhotoshopプラグインが流行りそうなくらいには面倒くささを感じる。

主要な分岐条件

ここまでの例でもすでに登場しているが、主要な条件として次の4種類がある。

  • Viewportのサイズ(viewport)
  • デバイスピクセル比(device pixel ratio)
  • 画像の形式(image format)
  • Art Direction(art direction)

これらの条件を、前述した要素・属性を組み合わせて駆使することで、状況に応じて最適な画像を読み込むための指定をおこなうことができる。

Viewportのサイズ(viewport)を条件にする

Viewport-based selectionとして仕様書に載っている。srcsetsizes を指定して条件を記述する。

次の例では sizes がメディアクエリを使った条件で、その結果 srcset 属性から適切なリソースが選ばれる。sizesvw というのはViewport Widthの略らしい。CSSピクセルとかじゃなくて%の扱い。

<img sizes="(max-width: 30em) 100vw, (max-width: 50em) 50vw, calc(33vw - 100px)"
      srcset="swing-200.jpg 200w, swing-400.jpg 400w, swing-800.jpg 800w, swing-1600.jpg 1600w"
      src="swing-400.jpg"
      alt="Kettlebell Swing">
  1. max-width:30emが真なら、Viewportの100%に近い画像をsrcsetから選ぶ
  2. max-width:50emが真なら、Viewportの50%に近い画像をsrcsetから選ぶ
  3. それ以外はViewportの33%から100px引いた値に近い画像をsrcsetから選ぶ

srcset の画像ファイル名の後ろのスペースをあけて 200w と書いてあるのは、その画像にリクエストしなくてもそのリソースがどの程度のwidthをもっているリソースなのかを判別材料にするためだろう。

デバイスピクセル比(device pixel ratio)を条件にする

Device-pixel-ratio-based selectionとして仕様書に載っている。<img>srcsrcset を指定して条件を記述する。次の例では、デフォルト画像のほかに srcset でピクセル密度が 1.5x のときと 2x のときに使う画像を指定している。

<img src="/uploads/100-marie-lloyd.jpg"
      srcset="/uploads/150-marie-lloyd.jpg 1.5x, /uploads/200-marie-lloyd.jpg 2x"
      alt="" width="100" height="150">

前述の sizesViewport-baseの説明を見る限り、pixel densityをよしなに計算して判定してくれるっぽい

画像の形式(image format)を条件にする

Image format-based selectionとして仕様書に載っている。<source>type を指定して条件を記述する。次の例ではJPGをデフォルトとして、対応していればWebPを読み込むように指定している。

<picture>
 <source srcset="/uploads/100-marie-lloyd.webp" type="image/webp">
 <img src="/uploads/100-marie-lloyd.jpg" alt="" width="100" height="150">
</picture>

Art Direction(art direction)を条件にする

Art direction-based selectionとして仕様書に載っている。<picture><soucrce> それに media を指定して条件を記述する。次の例では、min-width: 45emmin-width: 32em をそれぞれブレークポイントとして、いずれか適切な画像が読み込まれるように指定している。

<picture>
  <source media="(min-width: 45em)" srcset="large.jpg">
  <source media="(min-width: 32em)" srcset="med.jpg">
  <img src="small.jpg" alt="The president giving an award.">
</picture>

Art Directionだけ適切な訳語がわからなかったのでそのままで書いているが、これもメディアクエリを使えると思えばおそらく問題ない。(orientation:portrait) のような指定もできる。

条件を組み合わせる

これらの条件はもちろん複合条件として扱うことができる。

ここではそれらのサンプルを割愛するが、Responsive Images: Use Cases and Documented Code Snippets to Get You Startedに網羅的なパターンのサンプルが紹介されている。ここまで説明した内容を踏まえれば、見れば分かるはずなので、より詳しく知りたい人はご覧いただきたい。

対応状況

<picture> 関連仕様のブラウザ対応はやはりChromiumが先行気味だ。つい先日に公開された次の記事ではChrome 38 Betaで <picture> 要素をサポートしたことを記事冒頭で紹介している。Betaにきたということは、Stableまであと一歩ということでわりと近未来の話だ。

まさかのクラウドファウンディングで実現

This release adds support for the new element thanks to the hard work of community contributor Yoav Weiss, who was able to dedicate his time to implementing this feature in multiple rendering engines because of a successful crowdfunding campaign that raised more than 50% of its funding goal. Chromium Blog: Chrome 38 Beta: New primitives for the next-generation web

Yoav Weiss氏がクラウドファウンディングで資金を募って、これらの実装に貢献したらしい。いや、なんかクラウドファウンディングって凄いね。。。

Chrome, Firefox, Opera の開発版は対応済み

Picturefill 2.0: Use the picture element todayや、Can I use - picture elementを読むと分かるが、Chromium が先行気味なだけで、Firefox や Opera の Nightly Build でもすでにサポートされている。

その他ブラウザとPolyfill

WebKitには srcset 属性は実装済みのようだったので調べてみたところ、前述の Blink に関連実装をしたYoav Weiss氏のブログで、いくつかのブラウザについて言及されていた。中でも WebKit については、Safari 8 には入っていないものの <picture> 要素の対応を進めているようだ。

しばらくの間、Internet Explorer や Safari, iOS Safari, Android Browser の類は、<picture>srcset のPolyfillであるPicturefillを利用すれば良いかもしれない。

この Polyfill は Filament Group が開発していて Browser Support を見る限り、IE9やAndroid 2.3で若干の制約はあるようだが大体使える感じっぽい。(実際に運用したことはないので悪しからず)

まとめ

ひと通りすっきりした。

  • Chrome, Firefox, Opera はそのうち対応がくる
  • Safari, iOS Safari はさらにそのあと対応がきそう
  • Internet Explorer, Android Browser はよくわからない(AndroidはよChromeになれ)
  • 制作側にとっての仕様は固まってきている
  • 条件覚えるのはともかく、手書きするのつらそう
  • ツール作ったらワンチャンあるでこれ
  • Yoav Weiss氏がんばれ、超がんばれ

ここまで書いて気づいたのだが、本当に知りたかったのはResponsive imagesのための-webkit-image-set()で知った image-set() の行方だった気がしてきた。

ウロ覚えこわい。

参考URL