pictureタグでレスポンシブに画像の表示を切り替える方法
Webサイトを作成する際、画像のレスポンシブ対応は必須です。
画像のレスポンシブ対応には、多くの方法がありますが、srcset属性やpictureタグを使用することで、ユーザーが閲覧している端末に応じて最適な画像を表示することができます。
前回はimgタグのsrcset属性を使用した実装方法を紹介しましたが、今回はpictureタグを使った画像表示の切り替え方法をご紹介します。
特に、画面幅に応じて見た目の異なる画像を出し分ける必要がある場合は、pictureタグによる実装が適しています。その場合の実装方法などを、具体例を交えながら解説していきます。
pictureタグの使い方
pictureタグを使用すると、imgタグのsrcsetで画像を出し分けるよりも、さらに高度な表示条件を設定することが可能です。
任意の画面幅や画像ファイル形式のサポート状況などの条件に対して、確実に表示させたい画像を指定できます。
例えば、スマホとデスクトップで見た目が異なる画像の場合は、特定のブレイクポイントで確実に画像を切り替えたいため、pictureタグの使用が適しています。
このように、見た目の異なる画像をデバイス毎に出し分けて表示させることを「アートディレクション」といいます。
例として、以下のような2種類の画像パターンを表示する場合を考えてみます。
スマホデザイン用の画像
サイズバリエーション
- sp-image@560w.jpg (560 × 847px)
- sp-image@1120w.jpg (1120 × 1695px)
デスクトップデザイン用の画像
サイズバリエーション
- image@768w.jpg (768 × 508px)
- image@1024w.jpg (1024 × 678px)
- image@1536w.jpg (1536 × 1017px)
- image@2048w.jpg (2048 × 1356px)
画像はmax-width: 1024px
の親要素内で、width: 100%
で表示される想定としました
.container {
max-width: 1024px;
margin: 0 auto;
}
.image {
width: 100%;
height: auto;
}
pictureタグは以下のように記述します。(こちらのデモサイトで実際に表示確認できます)
<div class="container">
<picture>
<source
media="(max-width: 560px)"
srcset="./img/sp-image@560w.jpg 560w, ./img/sp-image@1120w.jpg 1120w"
sizes="100vw"
/>
<source
srcset="./img/image@768w.jpg 768w, ./img/image@1024w.jpg 1024w, ./img/image@1536w.jpg 1536w, ./img/image@2048w.jpg 2048w"
sizes="(max-width: 1024px) 100vw, 1024px"
/>
<img src="./img/image@1024w.jpg" class="image" alt="" />
</picture>
</div>
pictureタグは、任意の数のsourceタグと1つのimgタグで構成されます。
- sourceタグには、その画像が表示される条件と、条件にマッチした場合に表示する画像アセットを定義します。表示条件はmedia属性やtype属性で指定します。
- imgタグには、どのsourceタグでも画像を表示出来ない場合に代わりに表示する画像を指定します。画像に対するCSSスタイルやその他の属性もimgタグに記述します。
pictureタグでは、まず一番上のsourceタグから読み取られ、表示条件とマッチしない場合や画像が見つからなかった場合は、その下のsourceタグの評価に移っていきます。最終的にいずれのsourceタグとも表示条件が一致しない、もしくは画像が見つからなかった場合は、imgタグに指定した画像が表示されます。
上記の例では、一番上のsourceタグにmedia="(max-width: 560px)"
と条件を指定したので、画面幅560pxまでは、srcset属性に指定したスマホデザイン用画像(sp-image)の中から、適切なサイズの画像をブラウザが判定して表示します。
pictureタグ内のsourceタグにsrc属性を記述しても無効となるため、必ずsrcset属性で画像を指定する必要があります。(画像が一つしかない場合であっても)
また、sourceタグにcssスタイルを当てたり、alt等の属性を記述しても意味はありません。
sourceタグで読み込まれる画像に対しては、imgタグに記述したcssスタイルや属性が適用されます。
pictureタグは現在、主要なブラウザの全てでサポートされていますが、IE等の非対応ブラウザへ対応させたい場合は、picturefillなどのJavaScriptライブラリを使用してpictureタグをサポートすることができます。
pictureタグはmedia属性の他に、type属性で表示条件を指定することも可能です。
type属性を使うことで、WebPという軽量な画像フォーマットを、ブラウザの対応状況に応じて適切に表示させることができます。
srcset属性とpictureタグの違い
srcset属性はブラウザが自動で表示する画像を決定していますが、ブラウザ毎に画像の選定条件に差があります。そのため、開発者が表示させたい画像を完全にコントロールすることは出来ません。
srcset属性については以下の記事で詳しく解説しているので、あわせてご覧いただくと理解が深まります。
それに対し、pictureタグを使用する場合は、pictureタグ内のsourceタグに記述したmedia属性やtype属性の条件に対して、表示させたい画像を確実に指定することが出来ます。
また、media属性やtype属性の条件にマッチしたsourceタグの中で、さらにsrcset属性によりサイズ違いの画像を自動で出し分けることも可能です。
これらのことから、下記のようにして2つの方法を使い分けると良いでしょう。
- 同じ画像のサイズ違いのバリエーションを、解像度や画面幅に応じて出し分ける
- 見た目の異なる画像を画面幅に応じて出し分ける
- WebP形式の画像とその他の形式の画像を、ブラウザの対応状況に応じて出し分ける
pictureタグのCLS対策
Webページで画像を表示させる際は、CLS(Cumulative Layout Shift)に特に注意する必要があります。
CLS(Cumulative Layout Shift)とは、Webページの閲覧中に発生するレイアウトの変化の度合いを示す指標です。
imgタグ単体で使用する場合、width属性とheight属性を指定することで、ブラウザが画像を読み込む前に予め画像の表示スペースを確保しておくことができるため、CLSを防止することができます。
<img src="image.jpg" alt="" width="1024" height="678" />
pictureタグを使用する場合、pictureタグ内のそれぞれのsourceタグに個別にwidthとheightを設定可能です。
<picture>
<source
media="(max-width: 560px)"
srcset="sp.jpg"
sizes="100vw"
width="560"
height="847"
/>
<source
srcset="pc.jpg"
sizes="(max-width: 1024px) 100vw, 1024px"
width="1024"
height="678"
/>
<img src="./img/image@1024w.jpg" alt="" width="1024" height="678" />
</picture>
上記のコードの場合、画面幅560px以下で表示される画像にはwidth="560"
、height="847"
が、画面幅561px以上で表示される画像にはwidth="1024"
、height="678"
が適用されます。
sourceタグのwidth属性とheight属性の記述は省略することができますが、その場合は同じpictureタグ内のimgタグに指定したwidth属性とheight属性が共通で適用されます。全ての画像でアスペクト比が同じであればこれでも問題ありませんが、アスペクト比の異なる画像を出し分ける場合は、それぞれのsourceタグにwidth属性とheight属性を記述するようにしましょう。
ちなみにsourceタグのwidth, height属性は、MDNの英語版のドキュメントには説明が記載されているのですが、日本語版にはまだ記載されていませんでした(2023年4月時点)。
Can I use… を確認すると、現在では全てのブラウザに対応済みなので、使用しても問題はないはずです。
また、sourceタグのwidth, height属性は、pictureタグが親要素の場合のみ有効となるようです。
audioやvideoタグ内のsourceタグには効果がありません。
CLS対策としては、sourceタグにwidth, height属性を指定する方法の他に、CSSのaspect-ratioプロパティを使用する方法もあります。また、もし古いブラウザにも完全に対応させたい場合は、padding-topの%指定でアスペクト比を一定にした親要素内で絶対位置表示させるなどの実装が必要になるでしょう。
まとめ:pictureタグで画面幅に応じて画像を出し分けよう
pictureタグを使用して、画面幅に対してレスポンシブに任意の画像を表示する方法を解説しました。
今回の要点は以下の通りです。
- 画面幅によって見た目の異なる画像を出し分ける場合は、pictureタグの使用が適している
- pictureタグは任意の数のsourceタグと1つのimgタグで構成される
- sourceタグは上から順に表示条件が判定され、どの条件ともマッチしない場合、imgタグの画像が表示される
- sourceタグから読み込まれる画像も、imgタグに指定したCSSや属性の値が適用される
- sourceタグには個別にwidth属性とheight属性を指定することができ、アスペクト比の異なる画像を出し分ける場合でもCLSを防止できる
imgタグのsrcset属性とpictureタグを上手く使い分け、Webページのパフォーマンスを高めましょう!