`<img>` タグの使い方を改めて整理してみた

画像はWEBサイトの中で多く使われておりユーザにとっても重要な視覚情報の1つとなっています。
それゆえ適切な画像の設定がなされていないとページの表示速度が遅くなったり、画像読み込み時にレイアウトがずれるレイアウトシフトが起こるなどユーザにとってストレスの大きいものになってしまいます。

一方で`<img>` なんて基本的なタグでしょ！と思いつつ、様々な環境やデバイスに対応してちゃんと書こうとすると「ん？」となることが多いので備忘として改めて`<img>`の使い方を整理していきます。

# `<img>`タグの基本形
`src` を指定することで任意の画像を表示することができます。

```html
<img src="logo.jpg" />
```


画像が表示できない場合の画像の代替として`alt`を指定します。
これは、スクリーンリーダーを介してページにアクセスするユーザにとって役立ちます。
上記のコードを`alt`指定すると、次のようになります。

```html
<img src="logo.jpg"
 alt="sustenキャピタルマネジメントのロゴ"　/>
```

次に、`width`と`height`を追加し、画像の幅と高さを指定します。
```html
<img src="logo.jpg"
 alt="sustenキャピタルマネジメントのロゴ"　
 width="120" 
 height="50" >
```
画像に幅と高さを指定をすることで、画像がダウンロードされるまで、ブラウザでは画像用にスペースを確保します。
サイズの指定を忘れると、画像が読み込まれた際に、コンテンツが移動してレイアウトがずれる（レイアウトシフト）可能性があります。
最近のブラウザでは、画像の幅と高さからアスペクト比を自動で設定してくれるようになっているためCSS側でレスポンシブ対応をしていてもアスペクト比を保った状態で画像読み込み前の領域を確保してくれます。

# `srcset`属性の指定
標準の`<img>`タグでは表示できる画像のソースは1つです。
`srcset` や `sizes` 属性を使用すると、ブラウザが最も適切な画像を選択できるよう複数のソース画像を記述できます。
```html
<img src="logo.jpg"
    alt="sustenキャピタルマネジメントのロゴ"　
    width="120" 
    height="50"
    srcset="logo-2x.jpg 2x,
            logo-3x.jpg 3x"
```
`srcset`属性は、ブラウザが選択できる画像のセットと、各画像のサイズを定義します。
記述子に使える単位は、ビューポートの横幅 `w` か、デバイスピクセル比を表す `x` です。
画像を固定幅で表示させる場合はデバイスピクセル比（`1x`や`2x`）を指定します。

上記の例ではデバイスピクセル比が 2 の端末だと `logo-2x.jpg`、比率 3 なら `logo-3x.jpg`、 比率 1 なら `logo.jpg` という画像が読み込まれ表示されます。


# `sizes`属性の指定
```html
<img src="logo.jpg"
    alt="sustenキャピタルマネジメントのロゴ"　
    width="120" 
    height="50"
    srcset="logo-400w.jpg 400w,
            logo-800w.jpg 800w"
    sizes="(max-width: 640px) 400px,
            800px">
```

`sizes` 属性は`srcset`属性がある場合のみ記述でき、画面幅などの条件と、それらの条件が満たされたときに選択するのに最適な画像サイズを指定します。
`sizes` 属性を利用する時は`srcset`属性の記述子は必ず `w` の単位で記述します。

上記の例ではビューポート幅が 640px までの場合 400px で表示され 640px 以上の場合は 800px で表示されます。

# アートディレクション
`srcset`属性では同じ画像のさまざまなサイズをロードしますが、アートディレクションは、デバイス毎に見た目の異なる画像を読み込むことができます。 

アートディレクションを実現する方法として、`<picture>タグ` を使用して表示する画像形式を選択できます。
`<picture>`タグは、複数の`<source>`要素と1つの`<img>`要素をサポートし、 AVIF<sup>*1</sup> や WebP<sup>*2</sup> などのさまざまな形式の画像ソースを参照できます。

```html
<picture>
    <source srcset="logo.avif" type="image/avif">
    <source srcset="logo.webp" type="image/webp">
    <source srcset="logo.png" type="image/png">
    <img src="logo.jpg" alt="sustenキャピタルマネジメントのロゴ">
</picture>
```
ブラウザは各`<source>要素`を評価し、マッチするものがあれば`srcset属性`で指定された画像を表示します。
マッチするものがなかったり、ブラウザが`<picture>`要素に対応していない場合は、imgタグの画像が表示されます。imgタグの指定は必須です。

- *1: AV1 Image File Formatの略で、画像の超圧縮ができる次世代型画像ファイル形式
- *2: GoogleがWebサイトの表示速度短縮を目的として開発した画像フォーマット

# プリロード
`<link rel=preload>`を使用すると、ブラウザがHTMLで検出される前に、リソースを先読みすることができます。 

```html
<link rel="preload" as="image" href="logo.jpg">
```
ただし`<link rel=preload>`の利用は最小限にとどめ本当に必要なものを読み込ませるよう注意を払う必要があります。

# プレースホルダー
画像の読み込み中にユーザーにプレースホルダーを表示したい場合`<img>` の`background-image` と`background-size: cover`と組み合わせ要素の背景画像のサイズを設定し、画像を引き伸ばさずに画像を可能な限り大きく拡大縮小することができます。

プレースホルダーは、多くの場合、低品質の画像プレースホルダー（LQIP）またはSVG画像プレースホルダー（SQIP）であるインラインのBase64エンコードデータURLです。
これにより、ネットワーク接続が遅い環境でも、より鮮明な画像が読み込まれる前に、画像のプレビューを表示できます。

```html
<img src="keyvisual-800w.jpg"
    width="400"
    height="400"
    srcset="keyvisual-400w.jpg 400w,
            keyvisual-800w.jpg 800w"
    sizes="(max-width: 640px) 400px,
            800px"
    style="background-size: cover;
            background-image:
              url(data:image/svg+xml;base64,[Base64エンコードデータURL]);">
```

# 画像の遅延読み込み
`<img>`の`loading属性`を使用して、画像の読み込みタイミングを制御することができます。
`loading="lazy"`を指定すると、ビューポートから計算された距離に達したタイミングで遅延読み込みが可能となります。

以下は、`loading="lazy"`を使用した遅延読み込みの例です。

```html
<img src="keyvisual.jpg"
    alt="sustenキャピタルマネジメントのサイト"
    loading="lazy"
    width="1200"
    height="400">
```

遅延読み込みは、`srcset`でも機能します。

```html
<img src="keyvisual-800w.jpg"
    alt="sustenキャピタルマネジメントのサイト"
    width="1200"
    height="400"
    srcset="keyvisual-400w.jpg 400w,
            keyvisual-800w.jpg 800w"
    sizes="(max-width: 640px) 400px,
            800px"
    loading="lazy">
```


改めて整理すると奥の深い`<img>`タグ。
Next.jsやNuxtに実装されている画像コンポーネントはデフォルトでこれらの機能を取り入れているため普段はなかなか意識しませんが改めてちゃんと記述しようとすると忘れていることや気付きも多いと思いました。
これらを踏まえてよりよいユーザ体験につながるマークアップを意識していこうと思います。

## 参考
- [srcsetで画像をレスポンシブやRetinaディスプレイに最適化 \| BOEL Inc\. \| ブランディング&デザインファーム](https://www.boel.co.jp/tips/vol71/)
- [imgタグsrcset属性で画像出しわけ【レスポンシブイメージ】 \- GUAVAmemo](https://guavam.com/html-css/img-responsive/)
- [imgのsrcsetでレスポンシブで最適な画像を設定する方法 \| b\.](https://877.design/img-srcset/)
- [レスポンシブの画像切り替えができるsrcset属性│HTML│SYMMETRIC Web開発ブログ](https://www.site-convert.com/archives/1342)
- [HTMLのsrcset属性やpictureタグを使ったレスポンシブイメージを解説 \| 模写修行メディア](https://moshashugyo.com/media/responsive-img)
- [HTMLにimg要素で画像を表示する 2020年版 \- Qiita](https://qiita.com/hibikikudo/items/853aafe32ad7900712c8)
- [Cumulative Layout Shift を最適化する](https://web.dev/optimize-cls/#images-without-dimensions)
- [Setting Height And Width On Images Is Important Again — Smashing Magazine](https://www.smashingmagazine.com/2020/03/setting-height-width-images-important-again/)
- [Picture perfect images with the modern <img> element \- Stack Overflow Blog](https://stackoverflow.blog/2022/03/28/picture-perfect-images-with-the-modern-element/)
- [HTML5/埋め込み/img要素 レスポンシブイメージ（画像サイズの最適化） \- TAG index](https://www.tagindex.com/html5/embed/img_srcset_sizes.html)
- [srcset属性を使って画像をレスポンシブデザインに対応させる \| WEB PIXY](http://web-pixy.com/unclassified/responsive-images/)
- [HTML 5\.1のsrcset・sizes属性とpicture要素の使い方 \- レスポンシブイメージで画像表示を最適化 \- ICS MEDIA](https://ics.media/entry/13324/)
- [srcsetとsizes属性でサイズ\(解像度\)ごとに画像を出し分ける方法](https://junzou-marketing.com/srcset-sizes-attributes)