模写修行メディア

srcset/sizes属性やpictureタグを使ったレスポンシブイメージを解説

サイトを制作する際、画像の最適化は複雑でベストプラクティスがわからなかったり、疎かにしている人は多いのではないでしょうか?

  • レスポンシブイメージ
  • decoding="async"
  • loading='lazy'
  • レイアウトシフト
  • WebPやAVIF等の次世代画像フォーマット

画像周りでは知っておかないといけないことが多くあります。

この記事では、その中でも特にややこしい、srcset/sizes属性やpictureタグを使ったレスポンシブイメージを解説

👇 メンターやってます 👇

模写修行やこのメディアを作ったエンジニア中心に、メンタリングサービスHello Mentorを運営しています。

0からweb制作やプログラミングの勉強を始める方はもちろん、12ヶ月以上独学している方や既にお仕事をしている方にもご利用いただいています!

模写武者くんのアイコン
  • 独学に限界を感じている...
  • 何をどこまで勉強すれば良いかわからない...
  • 自分の書き方が正しいかわからない...
  • 検索しても解決しない問題が多い...
  • 転職や副業のアドバイスが欲しい...

このような方は、ぜひ下記のリンクからサービス詳細をご覧ください。無料相談もお気軽にお申し込みください。

※ 少人数運営のため人数制限あり ※

詳しいサービス内容を見る

入会金/解約料/契約期間の縛りなし

👆 メンターやってます 👆

この記事の目次

画像の最適化が大切な理由

webサイトはファイルサイズの多くを画像が占めるケースも少なくありません。

Googleは1ページあたり1.6MB程度のファイルサイズを推奨していますが、画像を上手く扱わないと簡単にオーバーしてしまいます。

  • 適切な画像フォーマットの使用
  • 画像の圧縮
  • レスポンシブイメージの使用

画像を多く使っているサイトであれば特に、これらをしっかりやるだけで、サイト全体のファイルサイズを大幅に減らすことが可能な場合もあります。

サイトのパフォーマンス(≒ 表示速度)は、ユーザービリティーやSEOにも関わる、重要な問題なので、出来る範囲で対応すべきです。

よくやりがちなNG例

  • とりあえず大きめの画像を使っておく
  • display: none;で画像を切り替える

これらはレスポンシブイメージ関連で、よくやりがちな代表的なNG例です。なぜ良くないのか、理由を紹介します。

とりあえず大きめの画像を使っておく

<div class="hoge">
    <img width="2000" height="1000" src="img/hoge.jpg" alt="..." class="hoge-img" />
</div>
.hoge{
    width: 90%;
    margin: 0 auto;
    max-width: 1000px;
}

.hoge-img{
    width: 100%;
    height: auto;
    vertical-align: bottom;
}

上の例では、高解像度ディスプレイに対応するために、とりあえず表示される最大サイズの2倍の画像を使っています。この場合、特定の環境下では無駄に大きな画像を読み込むことになってしまいます。

今回のケースでは、スクリーンサイズ360pxのスマホであれば、360px × 90% = 324pxが実際の表示サイズになります。3 倍まで用意しても、972pxの画像を用意すれば十分なところ、PC基準の2000pxの画像を読み込むことになってしまいます。

Point
この問題は後述する、srcset属性を使って解決します。

display: none;で画像を切り替える

<div class="hoge">
    <img width="2000" height="1000" src="img/hoge-pc.jpg" alt="..." class="u-pc hoge-img"/>
    <img width="1000" height="800" src="img/hoge-sp.jpg" alt="..." class="u-sp hoge-img"/>
</div>
.u-pc { display: none; }
.u-sp { display: block; }

@media only screen and (min-width: 768px) {
    .u-pc { display: block; }
    .u-sp { display: none; }
}

SP時とPC時で"見た目の違う"画像を使いたい場合、上の例のようにdisplay: none;で切り替える方法もNGです。この書き方は、SPで見た時もPCで見た時もどちらの画像も読み込んでしまいます。

display で出し分けるをしているデモです。DevTools の Network を開いてリロードしてみると、画像が 2 つとも読み込まれているのがわかります。

サイト内で1,2箇所くらいであれば、問題ないかもしれませんが、SP時とPC時で"見た目の違う"画像を多用するサイトでは、パフォーマンスに影響が出ることもあります。

Point
この問題は後述する、pictureタグを使って解決します。

レスポンシブイメージとは?

前のセクションで、NG例を紹介しました。NG例の問題点を解決するのがレスポンシブイメージです。

レスポンシブイメージとは、レスポンシブwebデザインでの画像の扱いのことです。

  • 適切なサイズの画像を出し分ける
  • 異なる見た目の画像を出し分ける

これらのことをHTMLだけで実装出来ます。次のセクションからこの2点に関して、詳しく解説します。

【初学者・中級者の方】独学に限界を感じてませんか?

プログラミングやデザインは独学可能ですが、ほとんんどの方が苦戦します。

↓このように感じていませんか?

  • 何をどこまで勉強すれば良いかわからない...
  • 自分の書き方が正しいかわからない...
  • 検索しても解決しない問題が多い...
  • 転職や副業するまでの道が見えない...

そんな問題を解決するために、模写修行やこのメディアを作ったエンジニア/デザイナー中心に、メンタリングサービスHello Mentorを始めました。

初級者から中級者まで対応できる、数少ないサービスです。

スクールのような大金は必要ありません。高額な費用は払いたくないけど、プロのサポートが欲しい方は、ぜひ下記のリンクからサービス詳細をご覧ください。

※ 少人数運営のため人数制限あり ※

詳しいサービス内容を見る

入会金/解約料/契約期間の縛りなし

👆 メンターは全員現役エンジニア 👆

srcset属性を使った画像の出しわけ

srcset属性を使った画像の出しわけ

昨今のデバイスは高解像度ディスプレイも多く、表示サイズと同じサイズの画像しか用意していないと、閲覧環境によっては画像が粗く見えます。

解像度 / Retinaディスプレイ(高解像度ディスプレイ) / デバイスピクセルとCSSピクセル / あたりの解説はわかりやすい記事を載せておきます。

どんな閲覧環境でもある程度、綺麗に見えて、パフォーマンスに影響がないようにする必要があります。そのために、srcset属性を使い、適切なサイズの画像を出し分けをします。

  • デバイス解像度のみで判断して出し分けするケース
  • ビューポートサイズとデバイス解像度で判断して出し分けするケース

srcset属性を使った出しわけは、この2パターンがあります。それぞれ解説します。

デバイス解像度のみで判断して出し分けするケース

<img
    width="200"
    height="100"
    srcset="img/200.png 1x, img/400.png 2x"
    src="img/400.png"
    alt="..."
/>
どんな時に使う?
画像を固定幅で表示する場合

画像を可変ではなく固定幅で表示させたい時は、デバイスの解像度で判断して適切な画像を出し分けます。

上の例は2倍まで対応した例です。srcset属性で2つの画像を指定しています。

ユーザー環境画像
デバイスピクセル比が1200.pngを表示
デバイスピクセル比が2400.pngを表示

ユーザーの環境に応じて、この表の出し分けをしていることになります。この時、必要な画像しか読み込まれないので、パフォーマンスに悪影響はありません。

下記は、デバイスピクセル比1~4まで対応したデモです。

デバイスピクセル比表示される画像
1横幅 200pxの画像
2横幅 400pxの画像
3横幅 600pxの画像
4横幅 800pxの画像

上の表のように表示されるはずです。

その他注意点

  • src属性はsrcset属性が非対応のブラウザ向けの記述
  • widthとheightはレイアウトシフト防止のために必要

レイアウトシフに関しては、下の記事をご覧ください。

レイアウトシフト(Cumulative Layout Shift)とは?対策・改善方法も紹介!

ビューポートサイズとデバイス解像度で判断して出し分けするケース

<div class="hoge">
    <img
        width="400"
        height="200"
        srcset="img/400.png 400w, img/800.png 800w, img/1200.png 1200w"
        sizes="(max-width: 1200px) 100vw, 1200px"
        src="img/1200.png"
        alt="..."
        class="hoge-img"
    />
</div>
.hoge{
    max-width: 1200px;
}

.hoge-img{
    width: 100%;
    height: auto;
    vertical-align: bottom;
}
どんな時に使う?
画像を可変幅で表示する場合
  • ビューポートサイズに対して100%で表示
  • 最大幅は1200px

例えば、このようなケースで使います。1200pxに達するまでは、常にビューポートサイズに対して100%の幅で表示しているので、画像自体の表示サイズは閲覧環境に依存します。

この方法も、解像度によって出し分けるケースと同じく、必要な画像しか読み込まれません。

srcset属性に関して

srcset="img/400.png 400w, img/800.png 800w, img/1200.png 1200w"

srcset 属性の部分だけ切り取りました。このように書くと、ブラウザが勝手に閲覧環境のビューポートサイズと解像度に応じて最適な画像を表示してくれます。

閲覧環境のビューポートサイズと解像度に応じて最適な画像を表示

この図だけ見ると、img/400.png 1xのような指定で良いように思いますが、これは図の状態がたまたま横幅400pxなだけです。可変なので閲覧環境によっては700pxになったり、1400pxになったりする想定です。

ポイントは図のようにビューポート(横幅)サイズだけでなく、解像度(デバイスピクセル比)も考慮してブラウザが表示する画像を決めてくれる点です。

srcset属性の書き方は、img/400.png 400wのように【画像ファイル・スペース・画像の幅のピクセル数】の順で書きます。画像の幅の単位はpxではなく、wを使う点に注意してください。実際に何pxの画像を使っているかなので、PCでサイズを確認して指定します。

WordPressでは、メディアから投稿した画像は、自動で数パターンのサイズで保存されます。表示する際も自動でsrcset属性が付与されます。

<img
    loading="lazy"
    class="..."
    src=".../hoge.jpg"
    alt="..."
    width="1600" height="1000"
    srcset=".../hoge.jpg 1600w,
    .../hoge.jpg-300x200.jpg 300w,
    .../hoge.jpg-1024x682.jpg 1024w,
    .../hoge.jpg-768x512.jpg 768w,
    .../hoge.jpg-1536x1023.jpg 1536w"
    sizes="(max-width: 1600px) 100vw, 1600px"
>

このような感じになっているはずです。

sizes属性に関して

sizes="(max-width: 1200px) 100vw, 1200px"

sizes属性の部分だけを切り取りました。sizes属性では画像の表示サイズを指定できます。

上の例の指定では、1200pxまではビューポートサイズに対して100%で、それ以外は1200pxの固定で表示しています。

ややこしいのですが、sizes属性は表示サイズを指定するためには使いません。

そうなると、下のような疑問がわきます。

  1. imgタグのwidthとheightはレイアウトシフト防止のために入れる
  2. 実際の表示サイズはCSSで指定する
  3. そしたらsizes属性は何のためにある?

sizes属性は不必要な気がしてしまいますが、実際は必要です。

重要!
sizes属性はsrcset属性で指定した画像の中のどの画像を表示するかブラウザが決める際に役に立ちます。

sizes="100vw"だけしか書かない場合や、sizes 属性を省略( = デフォルトの100vwが適応)した場合を例に解説します。

<!-- 例1 -->
srcset="..., img/1200.png 1200w, img/2400.png 2400w"
sizes="(max-width: 1200px) 100vw, 1200px"

<!-- 例2 -->
srcset="..., img/1200.png 1200w, img/2400.png 2400w"
sizes="100vw"

例1と例2は、共にデバイスピクセル比2まで対応するために、表示される最大のサイズ(=1200px)の2倍の画像まで用意しています。

これをデバイスピクセル比が1、ビューポートサイズが2400pxの環境で見ると結果は下記の表のようになります。

書き方表示される画像
例11200.png
例22400.png

表示される最大サイズが1200pxなので、デバイスピクセル比が1であれば、1200.pngが表示されてほしいのですが、例 2 ではそうなりません。

例1の場合
sizes属性で1200px以上は1200pxで固定にしているので、ブラウザは1200pxで見た時に最適なサイズを計算して画像を選んでいる
例2の場合
sizes属性で常に100vwにしているので、ブラウザは100vw = ビューポートサイズ = 2400pxで見た時に最適なサイズを計算して画像を選んでいる

上のようにブラウザが判断しています。

  • sizes属性は画像の出しわけのために必要
  • widthとheightはレイアウトシフト防止のために必要
  • 実際の表示サイズはCSSで設定する

まとめると上のようになります。

デモ

200~2000pxの間で200px刻みで画像を用意して、出し分けたデモを作りました。

幅を変えると画像が変わるのがわかると思います。ただし、※ ブラウザによって挙動が異なります。

例えばGoogle Chromeではキャッシュの仕様で、大きいサイズから小さいサイズに変更した際、リロードしない限り画像は切り替わりません。大きいサイズの画像を既に読み込んでるので、わざわざそれより小さい画像を読み込んで表示させる必要はないという考え方だと思います。

Google Chromeで確認する際は、小さいサイズから大きいサイズに変更して、確認してみてください。

その他注意点

  • src属性はsrcset属性が非対応のブラウザ向けの記述
  • sizes属性を使うときはsrcset属性は1xや2xではなく、200wや400wなどのサイズ指定でしか使えない

何パターンの画像を用意すべき?

何パターンの画像を用意すべきは悩ましいところです。

アナリティクスを導入しているサイトであれば、ユーザーの環境を調べて判断しても良いと思います。

デバイスの種類はかなりの数があり、全てに最適化するのは無理なので、個人的にあまり神経質にならなくても良いとは思います。

💡 例えば...

  • 画面に対して90%で中央配置
  • 最大幅は1000px

このような仕様であれば、3パターンくらい用意すれば良いのではないでしょうか?

360pxのスマホで見た際に画像は324pxで表示されます。デバイスピクセル比1のスマホは少ないので、324pxの画像は不要と判断します。

※ あくまで一例です

picture タグを使ったアートディレクション

pictureタグを使ったアートディレクション

バナーは全て画像にする想定です。この例のようにSPとPCで見た目の違う画像を表示したい場合、pictureタグを使います。

<picture>
    <source media="(max-width: 500px)" srcset="img/sp.png" />
    <source media="(max-width: 700px)" srcset="img/tb.png" />
    <img width="1600" height="800" src="img/pc.png" alt="" />
</picture>
  • 500px以下はsp.pngを表示
  • 700px以下はtb.pngを表示
  • それ以外とpictureタグ非対応のブラウザではpc.pngを表示

このように異なる見た目の画像を出し分ける方法をアートディレクションといいます。バナーやメインビジュアルなどで使う機会があります。

pictureタグを使うと、displayで切り替える方法と違って、表示する画像しか読み込まれないので、パフォーマンス的に良いです。

sizes属性で使うメディアクエリも同じですが、上から順番にマッチするか判断して、マッチしたらそれ以降は無視されるので、順番に気をつける必要があります。

また、srcset属性を使った出しわけと違ってブラウザが勝手に判断することはなく、必ず制作者の意図通りビューポートサイズに応じて出しわけが出来ます。

出し分ける画像が、全て同じ縦横比であれば、最後のimgタグにwidthとheightを記載すればレイアウトシフトは起こりません。しかし、縦横比の違う画像を使う場合は、レイアウトシフトが起こってしまいます。

これは諦めるか、CSSで予め領域を確保しておくなどの対策をするしかないです。

<div class="hoge">
    <picture>
        <source media="(max-width: 500px)" srcset="img/sp.png" />
        <source media="(max-width: 700px)" srcset="img/tb.png" />
        <img src="img/pc.png" alt="" class="hoge-img"/>
    </picture>
</div>
.hoge {
    aspect-ratio: 1000 / 800;
    ...
}

@media screen and (min-width: 500px) {
    .hoge{
        aspect-ratio: 800 / 800;
        ...
    }
}

@media screen and (min-width: 700px) {
    .hoge{
        aspect-ratio: 800 / 1600;
        ...
    }
}

このようにすればレイアウトシフトは防げます。

aspect-ratioについては、下記の記事をご覧ください。

縦横比(アスペクト比)を固定できるaspect-ratioについて具体例を交えて解説!

SP / TB / PCサイズで画像が切り替わるデモを作りました。

srcset属性とpictureタグの使い分け

srcset属性とpictureタグの使い分け

srcset属性とpictureタグ、どちらを使って出し分けるかの判断は、上の図のようになります。

ただし、下記のようにpictureタグを使ったアートディレクションで、srcset属性を使うこともできます。

<picture>
    <source
        media="(max-width: 500px)"
        srcset="img/sp.png 400w, img/sp@2x.png 800w"
    />
    <source
        media="(max-width: 700px)"
        srcset="img/tb.png 800w, img/tb@2x.png 1600w"
    />
    <img
        src="img/pc.png"
        srcset="img/pc.png 1600w, img/pc@2x.png 3200w"
        width="1600"
        height="800"
        alt="..."
    />
</picture>

CSSの背景画像の最適化はimage-setを使おう!

今まで、HTMLで画像を用事する方法を紹介してきましたが、CSSの背景画像として画像を入れたい場合もあります。

CSSの背景画像の最適化(出し分け)にはimage-setを使います。

CSS の背景画像を最適化!Retina ディスプレイ(高解像度)対応する方法

使い方は上の記事で詳しく紹介しています。

独学に限界を感じていませんか?

現役エンジニアによるメンタリングサービス作りました!

模写修行やこのメディアを作ったエンジニア中心に、メンタリングサービスHello Mentorを運営しています。

👇 こんな方のためのサービスです。

  • 独学に限界を感じている...
  • 何をどこまで勉強すれば良いかわからない...
  • 自分の書き方が正しいかわからない...
  • 検索しても解決しない問題が多い...
  • 転職や副業のアドバイスが欲しい...

メンターを務めるのは、今も現役でコードを書いているエンジニアのみです。駆け出しの方やメンターだけをやっている方はいません。

高額な料金はかかりません。サブスク / 契約期間の縛りなし / 入会金・解約料なしなので、リスクなく始められます。

少しでも興味がある方は、ぜひ下記のリンクからサービスサイトをご覧ください。無料相談もお気軽にお越しください。(無理な営業等一切ございません!)

※ 少人数運営のため人数制限あり ※

詳しいサービス内容を見る

入会金/解約料/契約期間の縛りなし

この記事を書いた人

Gakuのアイコン

Gaku / @gaku92014091

フリーランス8年を経て法人化(3期目)、業界歴は12年目。コンテンツ制作、ライティング、マーケティング、デザイン、コーディング、プログラミング(フロント)、幅広くやってます!webサービスを作るのが好き!

当メディア運営メンバーでメンターやってます!👉

詳しく見る

\Share/

模写修行のトップページのスクリーンショット
模写修行

実務レベルを体験するためのコーディング練習教材