TL;DR
- 油断すると忘れるのでメモ。
- MDNで久しぶりに読み直したら、メディア条件とスロット幅で腑に落ちた。
- 2xとかするとsizes無効ってか、w記述子でもピクセル密度に対応してたのが意外だった。
参考
See the Pen img srcset by Yasuo Fukuda (@sigwyg) on CodePen.
srcsetとは
ユーザーエージェントが 利用可能な、ソース画像のセットを示すリスト。提示されたリストはあくまでヒントです。実際にどの画像を選択するか、ユーザーエージェントには、かなりの裁量が与えられています。
多少条件が緩くても良しなに解釈してくれる。指定漏れやミスを許容できるファジーさが売り。(Media Queryだと絶対的なので、想定外に弱い)
確認方法
Chrome DevToolsだと、「Network」タブにて対象ファイルを選ぶと、Previewで確認できる。
- ページ再読み込みで確認できる(合致するリソースのみ読み込む)
- Chromeでテストするときはキャッシュ画像が優先されるので、[Disable cache]をオンにしておくこと
プレビュー画像そのものは実寸幅ではないので注意。この表示画像はDevToolsの表示サイズで拡大縮小される。よく見ると下のほうに 200x150 とあるので、そっちが実際のサイズを表している。
w 記述子を指定した場合
<img srcset="elva-fairy-320w.jpg 320w,
elva-fairy-480w.jpg 480w,
elva-fairy-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="elva-fairy-800w.jpg" alt="妖精の衣装を着たエルバ">
-
srcset
で表示画像の候補を指定する -
w
記述子は画像の実サイズ(表示サイズだと解像度の影響を受ける。MacだとCommand+iで分かる) -
sizes
にメディア条件とスロット幅(表示領域)を指定する - メディア条件が真となるとき、対応するスロット幅に最も近い画像が読み込まれる
-
sizes
の判定は記述順
「画面幅320px以下の場合に、280pxの領域に突っ込む」となる。
ブラウザはsrcsetにて提示された候補から、スロット幅に適用するのに最適な画像を選んで表示する。これには画面解像度も加味される。
なお、srcsetを解釈しないブラウザは、単純にsrcで指定されたリソースを読み込む。
x 記述子を指定した場合
<img srcset="elva-fairy-320w.jpg,
elva-fairy-480w.jpg 1.5x,
elva-fairy-640w.jpg 2x"
src="elva-fairy-640w.jpg" alt="妖精の衣装を着たエルバ">
- sizes は必要ない(混ぜるな危険)
- ブラウザーは、表示されている画面の解像度を単純に調べ、(srcsetで提示された候補から)最も適切な画像を提供する。
- 1xは暗黙のため、含める必要はない
注意点
- 幅記述子(
w
)と画素密度記述子(x
)を、同一の srcset 属性に混在させると無効になる - 重複した記述子も無効(
2x
が2つある場合など) - sizesの判定では、最初に一致した条件の後はすべて無視される(記述順に注意)
-
<meta name="viewport" content="width=device-width">
を設定していること
JavaScriptではできないのか?
JavaScriptを読み込んで解釈する前に、画像の先読みが開始している。JavaScriptで判定して出し分けようとすると、複数のリソースを読み込んでしまう。
CSSでやる場合
Media Queryで実装する。
いちお対応するリソースのみ読み込んでいる模様。(以前は全部読んでた気がする)
See the Pen Media Queryで個別に画像が読まれるか? by Yasuo Fukuda (@sigwyg) on CodePen.
こちらはsrcset
と違って厳密なので、良くも悪くも書かれた以上のことはしない。この例でいうと、ピクセル密度が3x
なiPhone Xとか、device-width: 375px
なiPhone 8 とか、414pxなiPhone 8 Plusとかは考慮しない。画面幅320px以下なら320pxの画像を適用する。
よくわからないこと
実際にはサイズ違いだけでなく、srcset
とsizes
でPC/SPで全く違う画像も提供できるため、picture要素を使う意義があまり見出せない。MIMEタイプのサポート状況で出し別けるのは便利だと思うが。
<picture>
<source type="image/svg+xml" srcset="pyramid.svg">
<source type="image/webp" srcset="pyramid.webp">
<img src="pyramid.png" alt="4つの正三角形から構築された通常のピラミッド">
</picture>