imgのsrcset属性について


TL;DR

  • 油断すると忘れるのでメモ。
  • MDNで久しぶりに読み直したら、メディア条件とスロット幅で腑に落ちた。
  • 2xとかするとsizes無効ってか、w記述子でもピクセル密度に対応してたのが意外だった。

参考

レスポンシブ画像の作り方 - MDN

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の画像を適用する。

よくわからないこと

実際にはサイズ違いだけでなく、srcsetsizesで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>