サイトを制作する際、画像の最適化は複雑でベストプラクティスがわからなかったり、疎かにしている人は多いのではないでしょうか?
- レスポンシブイメージ
- decoding="async"
- loading='lazy'
- レイアウトシフト
- WebPやAVIF等の次世代画像フォーマット
画像周りでは知っておかないといけないことが多くあります。
この記事では、その中でも特にややこしい、srcset/sizes属性やpictureタグを使ったレスポンシブイメージを解説します。
👇 メンターやってます 👇
模写修行やこのメディアを作ったメンバー中心に、Web制作業界を目指す方のための学習支援サービス 『Hello Mentor』 を運営しています。
- 基礎学習後にやるべきことがわからない...
- スクール卒だけど実力不足だと感じている...
- 自分のコードが正しい書き方かわからない...
- 未経験から1人で転職できる気がしない...
- 独立するためのノウハウがない...
特に上記のような方は、ぜひ下記のリンクからサービス詳細をご覧ください。
Hello MentorのLINEを登録すると、過去ウェビナーの一部をプレゼントしています。また、今後開催するウェビナーや講義にも無料で参加できるチャンスがあります。
👆 無料でプレゼント 👆
この記事の目次
画像の最適化が大切な理由
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の画像を読み込むことになってしまいます。
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時で"見た目の違う"画像を多用するサイトでは、パフォーマンスに影響が出ることもあります。
レスポンシブイメージとは?
前のセクションで、NG例を紹介しました。NG例の問題点を解決するのがレスポンシブイメージです。
レスポンシブイメージとは、レスポンシブwebデザインでの画像の扱いのことです。
- 適切なサイズの画像を出し分ける
- 異なる見た目の画像を出し分ける
これらのことをHTMLだけで実装出来ます。次のセクションからこの2点に関して、詳しく解説します。
基礎学習後...迷子になっていませんか?
Web制作業界を目指す方の多くが、基礎学習後にやるべきことがわからず、迷子状態になっています。あなたも下記のように感じていませんか?
- 基礎学習後にやるべきことがわからない...
- スクール卒だけど実力不足だと感じている...
- 自分のコードが正しい書き方かわからない...
- 未経験から1人で転職できる気がしない...
- 独立するためのノウハウがない...
そんな悩みを解決するために、模写修行やこのメディアを作ったエンジニア・デザイナー中心に、学習支援サービス 『Hello Mentor』 を運営しています。
転職成功者や副業・フリーランスデビューした方も出ています。
Hello MentorのLINEを登録すると、過去ウェビナーの一部をプレゼントしています。また、今後開催するウェビナーや講義にも無料で参加できるチャンスがあります。
👆 無料でプレゼント 👆
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つの画像を指定しています。
ユーザー環境 | 画像 |
---|---|
デバイスピクセル比が1 | 200.pngを表示 |
デバイスピクセル比が2 | 400.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属性は表示サイズを指定するためには使いません。
そうなると、下のような疑問がわきます。
- imgタグのwidthとheightはレイアウトシフト防止のために入れる
- 実際の表示サイズはCSSで指定する
- そしたらsizes属性は何のためにある?
sizes属性は不必要な気がしてしまいますが、実際は必要です。
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の環境で見ると結果は下記の表のようになります。
書き方 | 表示される画像 |
---|---|
例1 | 1200.png |
例2 | 2400.png |
表示される最大サイズが1200pxなので、デバイスピクセル比が1であれば、1200.pngが表示されてほしいのですが、例 2 ではそうなりません。
上のようにブラウザが判断しています。
- 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の画像は不要と判断します。
- 324px × 2 = 648px
- 最大幅の1000px
- 1000px × 2 = 2000px
※ あくまで一例です
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タグ、どちらを使って出し分けるかの判断は、上の図のようになります。
ただし、下記のように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
を使います。
使い方は上の記事で詳しく紹介しています。
基礎学習後...迷子になっていませんか?
模写修行やこのメディアを作ったメンバー中心に、Web制作業界を目指す方のための学習支援サービス 『Hello Mentor』 を運営しています。
下記のような、基礎学習後にやるべきことがわからず、迷子状態になっている方に特におすすめです
- 基礎学習後にやるべきことがわからない...
- スクール卒だけど実力不足だと感じている...
- 自分のコードが正しい書き方かわからない...
- 未経験から1人で転職できる気がしない...
- 独立するためのノウハウがない...
メンターは、全員が現役のプロです。駆け出しの方やメンターだけをやっている方はいません。
少数精鋭で運営しているため、受け入れ人数に限りがあります。本気でWeb制作業界を目指している方は、ぜひご検討ください。
Hello MentorのLINEを登録すると、過去ウェビナーの一部をプレゼントしています。また、今後開催するウェビナーや講義にも無料で参加できるチャンスがあります。
当メディア運営メンバーでメンターやってます!👉
詳しく見る
基礎学習後に迷子になっていませんか?脱初心者したいなら、私たちにお任せください!