imgのsrcset属性について

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

## 参考
[レスポンシブ画像の作り方 - MDN](https://developer.mozilla.org/ja/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images#Resolution_switching_Different_sizes#How_do_you_create_responsive_images)

<p data-height="265" data-theme-id="0" data-slug-hash="JJvmPw" data-default-tab="html,result" data-user="sigwyg" data-pen-title="img srcset" class="codepen">See the Pen <a href="https://codepen.io/sigwyg/pen/JJvmPw/">img srcset</a> by Yasuo Fukuda (<a href="https://codepen.io/sigwyg">@sigwyg</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## srcsetとは

ユーザーエージェントが 利用可能な、ソース画像のセットを示すリスト。提示されたリストはあくまでヒントです。実際にどの画像を選択するか、ユーザーエージェントには、かなりの裁量が与えられています。

多少条件が緩くても良しなに解釈してくれる。指定漏れやミスを許容できるファジーさが売り。（Media Queryだと絶対的なので、想定外に弱い）

## 確認方法

Chrome DevToolsだと、「Network」タブにて対象ファイルを選ぶと、Previewで確認できる。

- ページ再読み込みで確認できる（合致するリソースのみ読み込む）
- Chromeでテストするときはキャッシュ画像が優先されるので、[Disable cache]をオンにしておくこと

<img width="545" alt="スクリーンショット 2018-09-21 21.18.30.png (634.9 kB)" src="https://img.esa.io/uploads/production/attachments/4290/2018/09/21/13560/1ccda637-116a-4aeb-a94c-fbed4cd60d36.png">

プレビュー画像そのものは**実寸幅ではない**ので注意。この表示画像はDevToolsの表示サイズで拡大縮小される。よく見ると下のほうに 200x150 とあるので、そっちが実際のサイズを表している。

## w 記述子を指定した場合
```html
<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 記述子を指定した場合
```html
<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で実装する。
いちお対応するリソースのみ読み込んでいる模様。（以前は全部読んでた気がする）

<p data-height="265" data-theme-id="0" data-slug-hash="MoBvpa" data-default-tab="css,result" data-user="sigwyg" data-pen-title="Media Queryで個別に画像が読まれるか？" class="codepen">See the Pen <a href="https://codepen.io/sigwyg/pen/MoBvpa/">Media Queryで個別に画像が読まれるか？</a> by Yasuo Fukuda (<a href="https://codepen.io/sigwyg">@sigwyg</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

こちらは`srcset`と違って厳密なので、良くも悪くも書かれた以上のことはしない。この例でいうと、ピクセル密度が`3x`なiPhone Xとか、`device-width: 375px`なiPhone 8 とか、414pxなiPhone 8 Plusとかは考慮しない。画面幅320px以下なら320pxの画像を適用する。

## よくわからないこと

実際にはサイズ違いだけでなく、`srcset`と`sizes`でPC/SPで全く違う画像も提供できるため、picture要素を使う意義があまり見出せない。MIMEタイプのサポート状況で出し別けるのは便利だと思うが。

```html
<picture>
  <source type="image/svg+xml" srcset="pyramid.svg">
  <source type="image/webp" srcset="pyramid.webp"> 
  <img src="pyramid.png" alt="4つの正三角形から構築された通常のピラミッド">
</picture>
```