Webサイトのコーディングで、画面幅によって表示させる画像を変更したいとき、どのように対応していますか?
今までは .pc-only / .sp-only といった表示切替用のクラス名を用いて対応するのが一般的でした。
しかし、この方法では画面幅関係なくどちらの画像も読み込まれてしまうため、表示速度が遅くなる原因になっていました。
また、HTML・CSSにそれぞれ記述が必要で、複雑な切り替え方をしたいときに管理がしにくいという問題もあります。
そこで、今回ご紹介するpictureタグとsrcset属性の出番です。
pictureタグとsrcset属性を使うと、デバイスに応じて最適な画像だけを読み込むようにできるので、不必要な画像が読み込まれる心配はありません。
HTML側の記述のみでいろいろな設定ができるのですが、慣れていないと書き方に戸惑う方も多いと思うので、本記事では具体例も交えて分かりやすく解説したいと思います。
そもそも存在を知らなかった方、知ってはいたけど取っつきにくいと感じている方、必見です!
目次
デモページ
本記事で紹介しているソースの実際の挙動を確認できるデモページをご用意しました!
デモページを開く前の注意点ですが、ブラウザによって挙動が異なっていたり、キャッシュが強く残る場合があるため、「あれ、仕様通りにならないな」ということがあるかもしれません。
詳しくはブラウザによる挙動の違いについてをご一読ください。
検証用デモページはこちらになります。
検証用デモページ
imgとpictureの使い分け
まずはじめに抑えておきたいのが、「img」タグと「picture」タグの使い分けです。
どのように画像を出し分けるかによって、使用する画像タグも使い分けるのが推奨となっていますので、しっかり確認していきましょう。
「違う画像に切り替える」場合はpictureタグ + sourceタグ
「解像度を切り替える」場合はimgタグ + srcset属性
1違う画像に切り替える
デザイン上の都合で、画面幅に応じて違う画像に切り替える場合は、pictureタグ + sourceタグを利用します。
この「違う画像」というのが少し分かりづらいかもしれませんが、元画像が同じであっても、トリミング範囲や縦横比が違う場合はすべて「違う画像」としてお考え下さい。
2解像度を切り替える
同じ画像の解像度だけ変えたものを用意して、デバイスに応じて最適なサイズを読み込む、という目的の場合はimgタグ + srcset属性を利用します。
1 + 2画像も解像度も切り替える
ブレイクポイントで画像を別のものに切り替えて、さらにその中でも画面幅によって解像度を切り替える、という場合はpictureタグ + sourceタグ + srcset属性を利用する形となります。
それでは、それぞれの使い方についてさらに詳しくみていきましょう。
違う画像に切り替えるならpictureタグ + sourceタグ
画面幅によって表示させる画像を切り替えたい場合は、pictureタグとsourceタグを使います。
pictureタグとは
pictureタグとは、画面幅や閲覧する端末に応じた画像を表示させる要素です。
複数の「source」と1つの「img」をグルーピングするために使います。
pictureタグには主に以下の二つの機能があります。
・画面幅によって、表示する画像を切り替える
・ブラウザが対応していない形式の画像なら、別の画像を表示する
引用元:pictureタグで画像をレスポンシブに切り替える
閲覧するデバイスの画面幅によって、pictureタグの中のsourceタグに記載された条件を元に対応した画像を表示します。
使い方
まず、簡単に書き方をご紹介します。
pictureタグの中に、複数のsourceと1つのimgを囲んで使用します。
sourceの中の属性に記載された条件を元に、この中から条件に合った1つの画像が表示されます。
書き方には以下のルールがあります。
imgは1個のみ必須で入れる
sourceは0個以上、何個でも入れてOK
基本の記述は以下になります。
1 2 3 4 5 6 7 | <picture> <source srcset="img①URL" media="画面幅に応じた条件分岐" /> <source srcset="img②URL" media="画面幅に応じた条件分岐" /> <img src="img③URL" alt="~" /> </picture> |
実際に使用する際は、以下のように書きます。
1 2 3 4 5 6 7 | <picture> <source srcset="/img/img01.jpg" media="(min-width: 769px)" /> // 画面幅が769px以上の時(パソコン) <source srcset="/img/img02.jpg" media="(max-width: 768px)" /> // 画面幅が768px以下の時(タブレット) <img src="/img/img03.jpg" alt="画像" /> // ブラウザが対応していない形式の画像の場合imgを表示する </picture> |
表示する画像は以下の順で選ばれます。
画像を読み込む順番
sourceを上から一つずつ順番に読んでいく
sourceの属性に指定された条件を読み込む
条件が当てはまる ⇒ その条件のsourceを表示
条件が当てはまらない ⇒ 次のsourceを読むsourceのどれにも当てはまらなければ、一番最後のimgを表示する
設定する属性については、次の章で詳しく解説します。
sourceタグの属性を指定する
sourceタグの属性で、どの画面幅(端末)で、その画像を表示するか、という条件を指定します。
種類は3つあります。
画像URL(srcset)
メディアクエリ(media)
画像の形式(type)
中でも、画像URL(srcset)とメディアクエリ(media)は必須属性になります。こちらが無いと表示する画像が何なのか、いつ画像を切り替えるのか分からないので、必ず設定します。
画像URL(srcset)
srcsetは、画像のURLを指定します。imgタグでいう、srcに当てはまります。
書き方もimgタグのsrcと同じく、「/img/○○.jpg」などと書きます。
1 2 3 | <source srcset="/img/○○.jpg" /> |
詳しい書き方は「解像度を切り替えるならsrcset属性」の章で解説しています。
メディアクエリ(media)
media属性は、メディアクエリ(画面幅に応じた条件)を指定します。
CSSで特定の画面幅の時にだけ効かせたい時に、「@media screen and (min-width:769px)」などと記述する時と同じように、幅を指定します。
1 2 3 4 5 | <source srcset="/img/○○.jpg" media="(min-width: 769px)" /> // 幅769px以上の時表示 <source srcset="/img/▽▽.jpg" media="(max-width: 768px)" /> // 幅768px以下の時表示 <source srcset="/img/□□.jpg" media="(max-width: 640px)" /> // 幅640px以下の時表示 |
注意点として、sourceは上から順に読み込まれていくので、配置順を間違えないようにしましょう。
画像の形式(type)
type属性は、画像の形式を「MIMEタイプ」で指定します。
JPEG、PNG、GIFなどは全ブラウザで対応しているので、type属性を指定する意味はありませんが、WebPなど未対応ブラウザがある画像を入れ込みたいときに指定します。
1 2 3 4 5 6 | <picture> <source srcset="/img/○○.webp" type="image/webp" /> <img src="/img/sample.png" /> // ブラウザがWebpに対応していない時用の画像も指定 </picture> |
解像度を切り替えるならsrcset属性
解像度を切り替えたいならsrcset属性を使います。
MacやiPhoneなどといった高解像度ディスプレイ(Retinaディスプレイ等)の解像度は2倍なので、それに合った画像も必要になります。
書き方は以下の4つになります。
・デバイスピクセル比(解像度の大きさ)にあわせて別々の画像を読み込む
・画面幅(ビューポート)に応じて画像を切り替える
・sizes属性でサイズをコントロール
・条件分岐によるsizes属性のコントロール
引用元:srcsetとsizesで画像の種類とサイズを使い分ける(レスポンシブルデザイン)
MacやiPhoneなどといったApple製品に搭載されているディスプレイのこと。
通常のディスプレイと比べて解像度とコントラストの精度が高いのが特徴。
参照元:Macのパソコンでよく聞く「Retinaディスプレイ」とは
デバイスピクセル比(解像度の大きさ)にあわせて別々の画像を読み込む
通常のPC版とMacやiPhoneなどのRetinaディスプレイで画像を出し分ける場合は、以下のように書きます。
1 2 3 4 5 6 7 8 9 10 | //img + srcsetの場合 <img srcset="画像[1]小.jpg 1x, 画像[1]大.jpg 2x" src="画像[1]小.jpg" alt="画像"> // picture + sourceの場合 <picture> <source srcset="画像[1]小.jpg 1x, 画像[1]大.jpg 2x" media="(min-width: 769px)" /> <source srcset="画像[2]小.jpg 1x, 画像[2]大.jpg 2x" media="(max-width: 768px)" /> </picture> |
ポイントは、それぞれの画像の後ろに記載した「1x」と「2x」です。
1xは通常の解像度、2xがRetinaディスプレイなど2倍の解像度を指しています。
こちらを記載しないと出し分けは出来ないので、きちんと書く必要があります。
img + srcsetの場合
srcsetの後ろに書いているsrcは、srcsetに対応していないブラウザ用の記述になります。
srcsetがきちんと走れば、srcの画像は表示されないので画像が重複して読みこまれる心配はありません。
画面幅(ビューポート)に応じて画像を切り替える
画面幅に応じて画像を切り替える場合は、以下のように書きます。
1 2 3 4 5 6 7 8 9 10 | // img + srcsetの場合 <img srcset="画像[1]小.jpg 320w, 画像[1]大.jpg 640w" src="画像[1]小.jpg" alt="画像"> // picture + sourceの場合 <picture> <source srcset="画像[1]小.jpg 1200w, 画像[1]大.jpg 1400w" media="(min-width: 769px)" /> <source srcset="画像[2]小.jpg 320w, 画像[2]大.jpg 640w" media="(max-width: 768px)" /> </picture> |
img + srcsetの場合の画像パスの後ろに記載した「320w」や「640w」は画面幅が320pxや640pxの場合を指しています。
picture + sourceの場合の画像パスに記述した「1200w」や「1400w」は、メディアクエリに指定した画面幅の時、ユーザーの閲覧環境に応じて表示する画像を切り替えています。
閲覧環境が1200pxの場合は、1200wの記載がある画像[1]小.jpgが表示され、1400pxの場合は1400wの記載がある画像[1]大.jpgが表示されます。
こちらの記述は、以下の条件で切り替えを行います。
・画面幅が320pxまで ⇒ 画像[1]小.jpgを読み込む
・画面幅が640pxまで ⇒ 画像[1]中.jpgを読み込む
・画面幅がそれ以外の時 ⇒ srcの画像[1]大.jpgを読み込む
・画面幅が769px以上の時 ⇒ 横幅1200pxの画像[1]小.jpg または 横幅1400pxの画像[1]大.jpgを読み込む
・画面幅が768px以下の時 ⇒ 横幅320pxの画像[2]小.jpg または 横幅640pxの画像[2]大.jpgを読み込む
・画面幅がそれ以外の時 ⇒ srcの画像[3].jpgを読み込む
また、使用頻度は低そうですが、「w」のほかに「h」も使うことができます。
「320h」や「640h」などと指定すると、横幅ではなく縦の高さに応じて切り替えることが可能です。
解像度の判別も可能
1 2 3 4 5 6 7 8 9 10 | // img + srcsetの場合 <img srcset="画像[1]小.jpg 320w, 画像[1]大.jpg 640w" src="画像[1]小.jpg" alt="画像"> // picture + sourceの場合 <picture> <source srcset="画像[1]小.jpg 1200w, 画像[1]大.jpg 1400w" media="(min-width: 769px)" /> <source srcset="画像[2]小.jpg 320w, 画像[2]大.jpg 640w" media="(max-width: 768px)" /> </picture> |
srcsetの記述子「~w」を使用している場合、解像度は「1x」と判別されます。
Retinaディスプレイの解像度は2倍になるので画面幅が320pxの時、解像度は2倍の640pxになります。
img + srcsetの場合
Retinaディスプレイでは画面幅が320pxの時でも640wの時の条件が適応されるので、「画像[1]大.jpg」が表示されます。
しかし、この640wの記述が無いと320px以下のRetinaディスプレイでは画像が表示されないので注意が必要です。
つまり、320wと640wを一緒に使うことでデバイスピクセル比の1x・2xの役割も果たしていることになります。
sizes属性でサイズをコントロール
今まで紹介した書き方は、画面幅に対してどの画像を表示させるか、といった内容でしたが、
sizes属性を使うと「場面にあった画像のサイズも指定する」ことが出来ます。
書き方は以下になります。
1 2 3 4 5 6 7 8 9 10 | // img + srcsetの場合 <img srcset="画像[1].jpg 1400w, 画像[2].jpg 1200w" sizes="50vw" src="画像[3].jpg" alt="画像"> // picture + sourceの場合 <picture> <source srcset="画像[1]大.jpg 1400w, 画像[1]小.jpg 1200w" sizes="50vw" media="(min-width: 769px)" /> <source srcset="画像[2]大.jpg 640w, 画像[2]小.jpg 320w" sizes="50vw" media="(max-width: 768px)" /> </picture> |
画面幅が1200pxの時は「画像[2].jpg」が選択され、sizes属性の記述により、画面幅半分の600pxで表示されます。
画面幅が1400pxの時は「画像[1].jpg」が選択され、sizes属性の記述により、画面幅半分の700pxで表示されます。
こちらも、picture + sourceの場合はメディアクエリに指定した画面幅の時、ユーザーの閲覧環境に応じて表示する画像を切り替えています。
sizesの記述ルール
sizes属性の記述には以下のルールがあります。
・「画像の幅」ではなく「画面幅」に対して計算される
・srcset属性がある場合のみ記述できる
・sizesを利用する時はsrcsetの記述子は必ず「w」単位で書く
引用元:srcsetとsizesで画像の種類とサイズを使い分ける(レスポンシブルデザイン)
この中でもっと気を付けるべきなのは、一つ目の「画像の幅」ではなく「画面幅」に対して計算されるです。
画面幅が1920pxで1000px幅の画像があり、sizes属性に50vwと設定されている時、表示される画像のサイズは画面幅の半分の960pxで表示されることになります。
画像サイズの半分ではないので、気を付けましょう。
また、「sizesを利用する時はsrcsetの記述子は必ず「w」単位で書く」と書きましたが、「h」も使用することが可能です。
単位
sizesで使用できる単位は以下のものがあります。
・em
・rem
・px
・cm
・pt
その他にも「calc()」などの関数も使用できます。
割合指定
サイズを割合で設定したい場合、sizesでは%を使って指定することは出来ません。
その代わり、他の単位があります。
・vw…画面幅の横幅の長さを100%とした割合
・vh…画面幅の縦の長さを100%とした割合
・vmin…画面幅・縦横のどちらか小さい方に対する割合
・vmax…画面幅・縦横のどちらか大きい方に対する割合
スマホの場合は、vwとvhは縦向きと横向きによっては数値が変わります。
その中でも、vminとvmaxはブラウザ幅によって表示される基準が異なります。
例えば、画面幅が「375×600px」だとしたら、以下のような基準になります。
・vmin ⇒ 短い375pxを基準に算出
・vmax ⇒ 長い600pxを基準に算出
条件分岐によるsizes属性のコントロール
書き方は以下になります。
(見やすいよう途中で改行しています。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // img + srcsetの場合 <img srcset="画像[1].jpg 1400w, 画像[2].jpg 1200w, 画像[3].jpg 360w" sizes="(max-width: 360px) 100vw,(max-width: 800px) 75vw,50vw" src="画像[4].jpg" alt="画像"> // picture + sourceの場合 <picture> <source srcset="画像[1]大.jpg 1400w, 画像[1]小.jpg 1200w" sizes="(max-width: 1200px) 100vw,(max-width: 800px) 75vw,50vw" media="(min-width: 769px)" /> <source srcset="画像[2]大.jpg 640w, 画像[2]小.jpg 320w" sizes="(max-width: 640px) 100vw, (max-width: 360px) 75vw, 50vw" media="(max-width: 768px)" /> </picture> |
srcsetで画面幅によってどの画像を表示させるのかを指定、sizesで表示された画像をどのくらいまで広がるかを指定しています。
上記の内容だと以下の表示内容になります。
・画面幅が360pxまでの場合 ⇒ 「画像[3].jpg」が表示され、画面幅最大まで広がる
・画面幅が361~800pxの場合 ⇒ 「画像[2].jpg」が表示され、画面幅75%ほどのサイズまで広がる
・画面幅が801px以上の場合 ⇒ 「画像[1].jpg」、もしくは「画像[4].jpg」が表示され、画面幅50%ほどのサイズまで広がる
メディアクエリが無い50vwは、それ以前に書いたsizesのどれにも当てはまらない画面幅の時に適用されます。
ブラウザによる挙動の違いについて
ここまでpictureタグ等をご紹介してきましたが、ブラウザによっては上手く動作しない場合があるようです。
作成中のサイトにpictureタグなどを取り込みたいと思っている方は、一読ください。
Chromeの検証ツールではRetinaディスプレイ扱いになる可能性がある?
本来ならば、通常ディスプレイで確認したら通常ディスプレイと判別されるのですが
Chromeの検証ツールを開いた状態ですとなぜかRetinaディスプレイ扱いになることがあります。
ですので、画面幅を変えて確認するときは検証ツールを使用しない方法で確認した方が良さそうです。
ブラウザ別に挙動が異なる可能性がある
ブラウザによっては、挙動が異なる可能性があります。
以下の挙動が想定されますので、確認の際の参考にしてみてください。
Chrome : 大きなサイズの画像ファイルをキャッシュした場合、画面幅を狭めても小さい画像は読み込まれない
Firefox : 画面幅を変える度に、画面幅に適したサイズの画像を読み込む
Safari : 最初に開いた画面幅に応じた画像ファイルがキャッシュされ、画面幅を変えても画像は再読み込みされない
引用元:imgタグのsrcset・sizes属性とpictureタグの使い方 レスポンシブイメージで画像表示を最適化
まとめ
如何でしたでしょうか?
ディスプレイに合わせた記述など一見難しそうに思えますが、特段難しいことはしていないので
誰でも簡単に実装出来ると思います。
クラスの有無で画像を切り替えるのも1つの手ですが、冒頭でも記したように表示しない記述まで読み込まれてしまい、処理に時間がかかる原因になります。
pictureタグを使えばHTMLファイルだけの記述で切り替えられ、不要な記述を読み込まないのでHTML・CSSなどの容量も抑えられると思います。
少しでも、見て頂いた方の助けになれば幸いです。
参考サイト
pictureタグ レスポンシブに画像を切り替える
srcsetとsizesで画像の種類とサイズを使い分ける(レスポンシブルデザイン)
pictureタグとsrcset属性の違い。超わかりやすく