srcset属性でレスポンシブに画像の表示を切り替える方法

ウェブサイトを閲覧するユーザーの端末やデバイスは、様々なサイズや解像度を持っています。
画像の表示においては、ユーザーが閲覧している端末やデバイスの画面幅に合わせて最適なサイズの画像を表示することが重要です。

もし、デスクトップサイズでもモバイルサイズでも同じ画像を使用している場合は注意が必要です。
モバイルデバイス上で、デスクトップサイズを想定した画像をそのまま表示させると、必要以上に大きい画像を読み込むことになるため、Webページが重くなったり表示速度の低下につながります。

このようなケースの対策として使用されるのがimgタグのsrcset属性や、pictureタグです。
これらを使うことで、デバイスの画面幅や解像度などに応じて、適切なサイズの画像を選択して表示することができます。

異なるサイズの画像を用意する手間はありますが、モバイルファーストが重要視される時代において、今回の記事の内容は無視できない施策です。適切なサイズの画像を表示することで無駄なファイル読み込みをなくし、ページの表示速度を高速化させましょう。

目次

CSSで画像の表示・非表示を切り替える実装の問題点

画面幅に応じて表示画像を切り替えるやり方としては、srcset属性やpictureタグを使う以外の方法も考えられます。
例えば以下のコードのように、CSSのメディアクエリでdisplayプロパティを変更し、表示・非表示を切り替えるという方法です。

<img src="./img/image-small.jpg" class="sp" alt="" />
<img src="./img/image-middle.jpg" class="tablet" alt="" />
<img src="./img/image-large.jpg" class="pc" alt="" />
@media screen and (max-width: 559px) {
    .tablet,
    .pc {
        display: none;
    }
}
@media screen and (min-width: 560px) and (max-width: 1023px) {
    .sp,
    .pc {
        display: none;
    }
}
@media screen and (min-width: 1024px) {
    .sp,
    .tablet {
        display: none;
    }
}

この例では、画面幅(ビューポート)が559pxまではspクラスのみを表示、560px〜1023pxまではtabletクラスのみを表示、そして1024px以降はpcクラスのみを表示しています。

これにより、スマホサイズでは「image-small.jpg」、タブレットサイズで「image-middle.jpg」、デスクトップサイズで「image-large.jpg」を表示することができるのですが、この実装方法には1つ問題点があります。

このhtmlファイルをChromeで表示し、検証ツールのNetworkタブを開いて、このページで読み込まれるリソースを確認してみます。
(検証ツールは、Macの場合option+command+I、Windowsの場合はCtrl+Shift +IもしくはF12で開けます。)

display: none;のスタイルを当てても画像の読み込みは発生している様子

display: noneで非表示にした画像も、読み込みは発生します。
そのため、この例では実際にページに表示されるのは3つの画像の内の1つだけですが、内部的には3つ全ての画像の読み込みが発生しているのです。

そのため、例えば、スマホで閲覧しているユーザーに対しては「image-small.jpg」だけを使用できればいいのに、それよりも大きいサイズの画像も読み込むので、無駄な通信が発生することになってしまいます。

imgタグのsrcset属性やpictureタグを使用する方法では、実際に表示する画像だけを読み込みます。
そのため、画面幅に応じてレスポンシブに表示画像を切り替える際には、CSSで表示を切り替えるのではなく、以降で解説するsrcset属性かpictureタグを使用するようにしましょう。

imgタグのsrcset属性で画像を切り替える

imgタグで画像の出し分けを実装をする前に、サイズ違いの画像素材を用意しておく必要があります。
そのような場合、以下の記事で解説しているSquooshを利用すると、リサイズや圧縮などが同時に行えて便利です。

srcset属性の使い方

以下のコードは、imgタグのsrcset属性を使用して、画面幅に応じて画像を切り替える場合の記述例です。
(sizes属性については後ほど解説します)

<img
    srcset="
        ./img/image@400w.jpg 400w,
        ./img/image@768w.jpg 768w,
        ./img/image@1024w.jpg 1024w,
        ./img/image@1536w.jpg 1536w,
        ./img/image@2048w.jpg 2048w
    "
    src="./img/image@1024w.jpg"
    sizes="(max-width: 1024px) 100vw, 1024px"
    alt=""
    width="1024"
    height="683"
/>

400w, 768w, 1024w, 1536w, 2048wは、それぞれ対としてurlを記述している画像の幅(px)を表しています。(実際にページに表示される幅ではなく、画像素材そのものの幅です。単位はpxでは機能せず、幅記述子wで記述します)
例えば、”image@400w.jpg”は幅400pxの画像、”image@768w.jpg”は幅768pxの画像であることを宣言しています。ブラウザはウィンドウサイズに応じてこれらの画像セットの中から最適な画像を自動的に選定し、表示してくれます。

幅記述子wの指定では、ブラウザはデバイスピクセル比も考慮してくれます。
例えば、画面幅768pxのブラウザでこのimgタグを画面幅100%で表示する場合、通常は幅768pxに相当する”image@768w.jpg”が使用されます。
しかし、Retinaディスプレイなどのデバイスピクセル比が2のデバイスでは、幅768pxの2倍の、幅1536pxに相当する”image@1536w.jpg”が使用されます。

幅記述子wで表示条件を指定する方法の他に、1xや2xなど、デバイスピクセル比で指定することも可能です。
詳しくは以下の記事で解説しています。

srcset属性は、現在では主要なブラウザの全てでサポートされていますが、サポートされていないブラウザへの対応として、通常通りsrc属性も記述しておきます。

src属性はsrcset属性で画像が取得できなかった場合の保険にはなりません。
つまり、srcset属性がサポートされているブラウザでsrcset属性内のファイルパスが間違っていた場合、src属性の画像が表示されるのではなく、画像自体が表示されなくなります。
そのため、ファイルパスは間違いのないよう細心の注意を払いましょう。

sizes属性

srcset属性を幅記述子wで指定している場合、sizes属性を使用することが可能です。
(srcset属性内にwの記述が無い場合や、srcset属性自体がない場合、sizes属性は無効となります)

sizes属性を記述することで画像の表示サイズを指定でき、ブラウザはより正確な画像を選定することが可能になります。
例えば、最大幅1024pxの領域内で、画像を100%幅で表示したい場合、以下のように記述します。

<div class="container">
    <img
        srcset="
            ./img/image@400w.jpg 400w,
            ./img/image@768w.jpg 768w,
            ./img/image@1024w.jpg 1024w,
            ./img/image@1536w.jpg 1536w,
            ./img/image@2048w.jpg 2048w
        "
        src="./img/image@1024w.jpg"
        sizes="(max-width: 1024px) 100vw, 1024px"
        class="image"
        alt=""
        width="1024"
        height="683"
    />
</div>
.container {
    max-width: 1024px;
    margin: 0 auto;
}

.image {
    width: 100%;
    height: auto;
}

sizes属性はカンマ区切りで複数の表示条件を指定することができます。
例えば上記のコードでは、

  • 画面幅が1024pxまでの範囲では、ウィンドウ幅と同じ幅(100vw)
  • それ以外の画面幅では、常に幅1024px

でこの画像を表示することをブラウザに伝えています。(この場合、1024pxを超える画面幅のとき、デバイスピクセル比1では”image@1024w.jpg”、デバイスピクセル比2では”image@2048w.jpg”が表示されます)

sizes属性に指定した幅で画像が表示されるわけではありません。
sizes属性はあくまで「この画面幅の範囲では、この幅で表示するつもりだよ」ということをブラウザに伝えて、より最適な画像の選定を助けるものであり、実際の表示幅はCSSやimgタグのwidth属性で指定します。

表示確認

実際に画面がどのように読み込まれるか、Chromeの検証ツールで確認してみましょう。
(先程のimgタグを使用したデモサイトをこちらから確認できます)

検証ツールを開いたら、下の赤枠部分をクリックして、デバイスツールバーを開きます。

Chrome検証ツールでデバイスルールバーを表示する操作

デバイスツールバーの「Dimensions: ○○○○」をクリックして「Responsive」を選択します。
これにより、デバイスの幅や高さを自由に変更できるようになります。

Chrome検証ツールでレスポンシブモードにする操作

下の図の赤枠部分をクリックして「Add device pixel ratio」を選択すると、デバイスツールバーに「DPR: ○○」の項目が表示され、ここでデバイスピクセル比を変更することが可能になります(初期値は2.0)。
まずは分かりやすく、デバイスピクセル比 1.0 の場合で検証してみます。

Chrome検証ツールでデバイスピクセル比を表示するための操作

⬇︎

Chrome検証ツールでデバイスピクセル比が表示された様子

デバイスの横幅は768pxで設定しました。

Chrome検証ツールで画面幅を変更する操作

さて、このimgタグはwidth: 100%;のCSSにより、画面幅いっぱいになるよう表示させており、srcset属性には以下のように記述していました。

srcset="
    ./img/image@400w.jpg 400w,
    ./img/image@768w.jpg 768w,
    ./img/image@1024w.jpg 1024w,
    ./img/image@1536w.jpg 1536w,
    ./img/image@2048w.jpg 2048w
"

画像の表示幅は768px、デバイスピクセル比は今回 1.0 のため、srcset属性の中から幅記述子768wで指定した”image@768w.jpg”が選定されることが期待されます。

ページで読み込まれるリソースを確認するため、「Network」タブを開き、ページをリロードします。

画面幅に応じて適切なファイルだけが正しく読み込まれた様子

上の画像の通り、幅記述子768wで指定した”image@768w.jpg”だけをブラウザが自動で読み込んでくれました。

他の条件についても確認すると、以下の表のようになるはずです。

デバイスピクセル比ページ表示時の画面幅読み込まれた画像 (srcsetの幅記述子)
1~ 400pximage@400w.jpg (400w)
1401px ~ 768pximage@768w.jpg (768w)
1769px ~image@1024w.jpg (1024w)

(画面幅を変えながら確認した場合や、デバイスピクセル比が 2 以上の場合は、意図した結果と異なる可能性があります。詳しくは次の「注意点」で解説しています)

注意点

srcset属性の中からどの画像が使用されるかは、ブラウザによって自動的に決定されます。そのため、ブラウザが違えば、画像の選定のされ方も異なる点に注意が必要です。

以下に例として2つの挙動の違いを記載しました(2023年4月時点での調査結果です)

画面幅を変更した際の挙動の違い

Webページを閲覧中にブラウザのウィンドウ幅を変更させた場合、srcset属性での画像の読み込み方には、ブラウザ毎に以下の仕様の違いがあります。

  • Chrome, Edge:画面幅を狭めた場合、最初に読み込んだ画像より小さい画像は読み込まれない。画面幅を広げた場合、最初に読み込んだ画像より大きい画像は必要になったら読み込まれる。
  • Firefox:画面幅を変えるたびに、最適なサイズの画像を読み込む
  • Safari:画面幅を変えても、最初に読み込んだ画像ファイルが使用され、他の画像の読み込みは発生しない

デバイスピクセル比 2 の場合の挙動の違い

デバイスピクセル比が 1 の場合は、Chrome, Edge, Firefox, Safariのどのブラウザにおいても、ページ表示時の画面幅と読み込む画像の関係は上述した表と同じ結果が得られました。

しかし、デバイスピクセル比が 2 以上になると、画面幅に応じて読み込む画像にブラウザ毎の差異が生じます。

Firefox, Safariの場合

デバイスピクセル比ページ表示時の画面幅読み込まれた画像 (srcsetの幅記述子)
2~ 200pximage@400w.jpg (400w)
2201px ~ 384pximage@768w.jpg (768w)
2385px ~ 512pximage@1024w.jpg (1024w)
2513px ~ 768pximage@1536w.jpg (1536w)
2769px ~image@2048w.jpg (2048w)

Chrome, Edgeの場合

デバイスピクセル比ページ表示時の画面幅読み込まれた画像 (srcsetの幅記述子)
2~ 277pximage@400w.jpg (400w)
2278px ~ 443pximage@768w.jpg (768w)
2444px ~ 627pximage@1024w.jpg (1024w)
2628px ~ 886pximage@1536w.jpg (1536w)
2887px ~image@2048w.jpg (2048w)

FirefoxとSafariの場合は分かりやすい仕様になっていますが、ChromeとEdgeの場合はもう少し複雑な計算をもとに画像が選定されているようです。

画像選定のためにどんな計算が行われているかを知っておく必要はありませんが、こちらの記事に詳しい算出方法が載っていたので、興味のある方はご覧になってみてください。

ここで重要なのは、srcset属性からどの画像が選ばれるかは、完全な予測ができないということです。
上記の検証結果はあくまで一例であり、今後ブラウザのバージョンアップなどで変わってくる可能性もあります。

そのため、どの画像が表示されても問題がないよう、srcset属性は見た目が同じ画像のサイズ違いを出し分けるために使用するべきです。見た目が違う画像を出し分けるのは、意図していない画像が表示される可能性があるため推奨されません。そのようなケースはpictureタグを使用しましょう。

WordPressでレスポンシブに画像を出し分ける

WordPressに画像をアップロードすると、その画像のサイズ違いのバリエーションが自動的に作られます。

そして、ページの編集画面で画像を挿入すると、自動的に生成された複数サイズの画像の内、適切なサイズのものが選ばれるようにimgタグにsrcset属性が自動で付加されます。

そのため、WordPressのページエディターで画像を挿入する場合においては、複数サイズの画像を用意したり、srcset属性の記述を行うといった手間は必要はありません。

エディターで挿入した画像がどのようなimgタグで出力されるかは、テーマやプラグインによって変わります。
ここでは例として、デフォルトテーマのTwenty Twenty-Threeを使用した場合に出力されるimgタグを見てみます。

ブロックエディタの画像ブロックで、4000 × 4000 pxの画像を挿入してみました。

WordPressの画像ブロックで画像を挿入している様子

この画像は以下のようなimgタグで出力されます。

<img
    decoding="async"
    width="1024"
    height="1024"
    src="http://localhost:10024/wp-content/uploads/2023/03/image-1024x1024.png"
    alt=""
    class="wp-image-29"
    srcset="
        http://localhost:10024/wp-content/uploads/2023/03/image-1024x1024.png 1024w,
        http://localhost:10024/wp-content/uploads/2023/03/image-300x300.png    300w,
        http://localhost:10024/wp-content/uploads/2023/03/image-150x150.png    150w,
        http://localhost:10024/wp-content/uploads/2023/03/image-768x768.png    768w,
        http://localhost:10024/wp-content/uploads/2023/03/image-1536x1536.png 1536w,
        http://localhost:10024/wp-content/uploads/2023/03/image-2048x2048.png 2048w
    "
    sizes="(max-width: 1024px) 100vw, 1024px"
/>

幅150px、300px、1024pxの画像についてはそれぞれ、サムネイルサイズ、中サイズ、大サイズに相当する画像であり、設定によって変更可能です。大サイズで設定した幅の2倍サイズの画像も生成されます(この例では幅2048px)

幅768px、1536pxの画像については、設定に関わらず生成されるバリエーションです。768pxはタブレット表示用のブレイクポイントとしてよく使用される数値で、1536pxはその2倍になります。

もともとの画像のサイズより大きいサイズのバリエーション画像は生成されません。例えば、幅400pxの画像をアップロードした場合は、幅150pxと300pxの画像のみ追加生成されます。

画像のサイズバリエーションは、「設定」→「メディア」にて変更することが可能です。
サムネイルサイズ、中サイズ、大サイズ、それぞれのバリエーションにおける幅と高さの上限を指定できます。

WordPressのメディア設定画面

設定を変更した場合、それ以降アップロードされた画像に対してのみ設定内容が反映されます。

pictureタグでレスポンシブに画像を出し分ける

pictureタグを使用することでも、画面幅に応じた画像の切り替えが可能です。

imgタグのsrcset属性では、どの画像が読み込まれるかはブラウザによって一任されていましたが、pictureタグの場合、どの画面幅の範囲でどの画像を読み込むかを完全に制御することが出来ます。

そのため、「スマホでは縦長デザインの画像、PCでは横長デザインの画像」といった具合に、見た目の違う画像を画面幅に応じて出し分けることが可能になります。

詳しい実装方法は、こちらの記事で解説しています。

まとめ:srcset属性で画面幅に応じて画像を出し分けよう

画面幅に応じてレスポンシブに画像表示を切り替える方法について解説しました。
今回の記事の要点は以下の通りです。

  • 画面幅に応じてレスポンシブに適切な画像を表示するには、imgタグのsrcset属性かpictureタグを使用する
  • CSSで画像の表示/非表示を切り替える方法は、非表示の画像の読み込みも発生するため非推奨
  • srcset属性の中からどの画像が選択されるかはブラウザによって挙動の違いがある
  • WordPressは自動でサイズ違いの画像生成とsrcset属性の付与を行う
  • srcset属性は”同じ画像のサイズ違い”を出し分けるために、pictureタグは”違う画像”を出し分けるために使用する

画面幅によって最適な画像を読み込むように実装し、無駄なファイル読み込みをなくしましょう!

内容が良かったらSNSでシェアしていただけると嬉しいです!
目次