<picture> 要素とは
<picture> 要素は、画像リソースの読み込みを宣言的に行う仕組みです。Web 開発者はこの要素によって、CSS や JavaScript によるハックなしに、レスポンシブデザインで画像を扱えるようになります。また、画像リソースの読み込みがネイティブに実装・最適化されたのは、遅いモバイル回線でページを見ているユーザーにも嬉しいことです。これはとくに重要でしょう。
<picture> 要素と、新しく <img> に追加された srcset と sizes 属性を使えば、画像リソースを柔軟に指定できます。レスポンシブデザインのサポートとページ読み込み時間を短くするため、どの状況下でどの画像を読み込むかはブラウザにまかせてしまいましょう。私たちは、今から紹介する画像の使われ方にもとづいて、わかりやすい HTML を書くだけです。
- アートディレクションによる選択
- モバイルデバイス(縦向き)用、ワイドデスクトップモニター用と、表示される画面によって画像を出し分けたいですか?でしたら画面の大きさごとに最適化された画像を読み込むようにしましょう。
- デバイスピクセル比による選択
- 表示されるデバイスが高DPIなディスプレイかによって画像を出し分けたいですか?でしたら高解像度の画像を読み込むようにしましょう。
- ビューポートによる選択
- ウインドウの一定割合を画像が占めるようにしたいですか?でしたら画像をビューポートの大きさに合わせて表示させましょう。
- 画像フォーマットによる選択
- ファイルサイズが小さいなど、パフォーマンスを向上させる新しい画像ファイル形式をサポートしているかによって画像を出し分けたいですか?でしたらWebP などの別のファイル形式を読み込むようにしましょう。
アートディレクションでの利用
<picture> 要素が最も使われるケースは、レスポンシブデザインにおいて「アートディレクション」と呼ばれるものです。これは、ひとつの画像をビューポート幅に応じて拡大縮小するのではなく、ビューポートの大きさにあわせ用意した複数の画像を使うものです。
リソース読み込みのパフォーマンスを改善する
<picture> 要素、もしくは srcset 属性と sizes 属性を持つ <img> 要素を使うと、ブラウザは明示的に指定された条件にマッチする画像のみをダウンロードします。この実装は HTML パーザ互換で、ブラウザの画像キャッシュ機能と先読み機能の恩恵に預かれます。
<picture> のデモ
インターネットが猫の画像を提供するために作られたことはご存知ですよね。<picture> を使うと、どんな隙間にも入り込んでしまうという猫の特徴をエミュレートできるのです。
Chrome 38 以上でデモを新しいタブで開いてください。開いたら、ウインドウを大きくしたり小さくしてみて、猫がどうなるかを確認してみてください。
このデモは <picture> がもたらす機能のほんの一部をお見せしたに過ぎません。さて、ではまず構文から見ていきましょう。
<picture> の構文
デモで使った HTML と CSS は、たったこれだけです。
<style>
img {display: block; margin: 0 auto;}
</style>
<picture>
<source
media="(min-width: 650px)"
srcset="images/kitten-stretching.png">
<source
media="(min-width: 465px)"
srcset="images/kitten-sitting.png">
<img
src="images/kitten-curled.png"
alt="a cute kitten">
</picture>
このコードには JavaScript やサードパーティ製のライブラリが使われていません。CSS については <style> 要素がありますが、<img> 要素のスタイルを少し触っただけで、メディアクエリーなどはありません。<picture> 要素のネイティブ実装では、レスポンシブイメージは HTML だけで指定するのです。
<source> 要素を使う
<picture> 要素にはなんの属性も定義されていません。魔法が起こるのは、<source> のコンテナとして <picture> が使われたときです。
<source> 要素はビデオやオーディオなどの読み込みに使われていましたが、画像の読み込みにも対応するように拡張され、さらに次の新しい属性も追加されました。
- srcset(必須)
-
画像がひとつの場合は、そのファイルのパスを指定します(例:
srcset="kitten.png")。画像を複数指定する場合は、ファイルのパスとピクセル密度デスクリプタの組み合わせを、カンマで区切って指定します(例:
srcset="kitten.png, kitten@2X.png 2x")。ファイル名のみでデスクリプタがない場合、そのファイルは 1x が指定されたものとみなされます。使い方はピクセル密度デスクリプタと組み合わせる例をご覧ください。
- media(任意)
-
CSS の
@mediaで使うメディアクエリーを指定します(例:media="(max-width: 30em)")。使い方は <picture> の構文にある例をご覧ください。
- sizes(任意)
-
幅デスクリプタのみ(例:
sizes="100vw")、もしくは、メディアクエリーと幅デスクリプタの組み合わせ(例:sizes="(max-width: 30em) 100vw")を指定します。メディアクエリーと幅デスクリプタの組み合わせはカンマで区切って複数指定できます(例:
sizes="(max-width: 30em) 100vw, (max-width: 50em) 50vw, calc(33vw - 100px)")。このとき、最後の組み合わせが規定値になります。使い方は幅デスクリプタと組み合わせた例をご覧ください。
- type(任意)
-
MIME を指定します(例:
type="image/webp"、type="image/vnd.ms-photo")。使い方は新しい画像フォーマットを読み込む例をご覧ください。
ブラウザはこれらの属性に指定された値をヒントに、もっとも適切な画像リソースを読み込みます。要素の記述順は重要です。なぜならブラウザは条件にマッチした <source> 要素のうち最初のものを読み込み、他の <source> を無視するからです。
最後に <img> 要素を指定する
<picture> 要素の導入にあわせ、<img> 要素が<picture> 要素のフォールバックとして使えるように更新されました。ブラウザが <picture> 要素をサポートしていない場合や、<source> 要素がマッチしない場合に、<picture> 要素内の <img> 要素が使われます。 <picture> 内の <img> は必須です。もし忘れた場合、画像は表示されません。
<picture> のデフォルト画像は、<img> に指定しましょう。ここで、<img> は <picture> の一番後ろに書かなければなりません。なぜなら <img> の後に <source> が書かれた場合、それらの <source> はすべて無視されるからです。
また、画像が表示されない場合のフォールバックにも <img> 要素が使われます。<img> の alt 属性に代替テキストを指定しましょう。
ピクセル密度デスクリプタを使う
高解像度のディスプレイをサポートサポートするには、1x、1.5x、2x、3x といったピクセル密度デスクリプタを使います。srcset 属性 は <img> 要素 <source> 要素どちらでも使えます。
次の例は、1x、1.5x、2x な画面に対応させるコードです。
<picture>
<source
media="(min-width: 650px)"
srcset="images/kitten-stretching.png,
images/kitten-stretching@1.5x.png 1.5x,
images/kitten-stretching@2x.png 2x">
<source
media="(min-width: 465px)"
srcset="images/kitten-sitting.png,
images/kitten-sitting@1.5x.png 1.5x
images/kitten-sitting@2x.png 2x">
<img
src="images/kitten-curled.png"
srcset="images/kitten-curled@1.5x.png 1.5x,
images/kitten-curled@2x.png 2x"
alt="かわいい子猫">
</picture>
幅デスクリプタを使う
Web Fundamentals では新しく追加された sizes 属性を <img> 要素で使う例が詳しく紹介されています。
画像の最終的に表示される大きさがわからないと、画像ソースのピクセル密度デスクリプタが指定しづらい場合があるでしょう。ウインドウの大きさに応じて画像を可変させたい場合はとくにです。
固定された画像の大きさと密度を指定しなくても、画像の表示される大きさは、幅デスクリプタと画像のもとの大きさを提供すれば計算できます。指定された値からブラウザが有効なピクセル密度を計算し、最も適した画像をダウンロードするわけです。
次の例は、sizes 属性を使い、画像を常にビューポートの幅80%で表示する画像ですが、srcset と組み合わせ、幅の違う灯台の画像4つ(160px, 320px, 640px, 1280px)からひとつを提供するように指定しています。
<img src="lighthouse-160.jpg" alt="灯台"
sizes="80vw"
srcset="lighthouse-160.jpg 160w,
lighthouse-320.jpg 320w,
lighthouse-640.jpg 640w,
lighthouse-1280.jpg 1280w">
ブラウザは与えられたヒントと、ビューポートの幅とハードウェアの画面解像度に基づき、最も適切な画像リソースを選び読み込みます。
<picture> の登場により、sizes 属性は <img> 要素と <source> 要素のどちらにも使えるようになりました。
<picture>
<source media="(min-width: 800px)"
sizes="80vw"
srcset="lighthouse-landscape-640.jpg 640w,
lighthouse-landscape-1280.jpg 1280w,
lighthouse-landscape-2560.jpg 2560w">
<img src="lighthouse-160.jpg" alt="灯台"
sizes="80vw"
srcset="lighthouse-160.jpg 160w,
lighthouse-320.jpg 320w,
lighthouse-640.jpg 640w,
lighthouse-1280.jpg 1280w">
</picture>
ここでは先の例を更新し、ビューポートの幅が 800px 以上の場合、横長の写真を表示するようにしています。
ほかの画像フォーマットを読み込む
<source> 要素の type 属性は、すべてのブラウザでサポートされていないような画像を読み込むのに使えます。たとえば、WebP フォーマットをサポートしているブラウザには WebP 画像を、サポートしていないブラウザには JPEG 画像を提供するといったことができます。
<picture> <source type="image/webp" srcset="images/butterfly.webp"> <img src="images/butterfly.jpg" alt="蝶"> </picture>
コードサンプルAdditional code examples
Dev.Opera のブログ記事「Responsive Images: Use Cases and Documented Code Snippets to Get You Started」では<picture> と <img> 要素、それに srcset、media、sizes、type 属性をそれぞれ組み合わせた例を網羅し紹介しています。
使ってみよう
<picture> 要素は Chrome 38 から利用できます。Chrome DevTools のスクリーンエミュレーション機能でテストしてみましょう。
この機能へのフィードバックがあれば、Chrome バグトラッカーまでお願いします。
<picture> も使い、他のブラウザにもレスポンシブイメージを提供したい場合は、<picture> と共に polyfill を使ったサンプルがありますのでそちらをご覧ください。
Web Fundamentals の画像についての記事では、Web での画像の利用についてベストプラクティスや例が紹介されています。こちらもあわせてご覧ください。