画像の出し分けで失敗しない!レスポンシブ環境での最適化テクニック|現場で使える実践テクニック

画像の出し分けで失敗しない!レスポンシブ環境での最適化テクニック|現場で使える実践テクニック
C
クリオ
Web制作ディレクター / フロントエンジニア

こんにちは!
今日は「画像の出し分けで失敗しない!レスポンシブ環境での最適化テクニック」について解説します。

レスポンシブデザインを実装するとき、皆さんは画像をどう扱ってますか?
実は、ここが初心者さんがめっちゃつまずきやすいポイントなんです。

スマホで重い画像を読み込む罪

僕が新入社員だった頃、こんなことがありました。
PCで見るともりもりのデザインになった、めっちゃ大きな画像をそのまま全デバイスで読み込ませちゃったんです。
そしたら、スマホでの読み込み速度が遅いって指摘を受けてしまいました。

これ、実はよくある勘違いなんです。
「レスポンシブだからCSSでwidth: 100%にしたら大丈夫」って思ってる人、結構多いんですよ。
でも、CSSで画像のサイズを縮小しても、ブラウザが読み込むファイルサイズは変わらないんです。
つまり、スマホで320pxの幅で表示する場合でも、PCの1920px用に作られた5MBの画像をダウンロードしてるわけですよ。
ほんま無駄です。

スマートフォンのユーザーは通信速度が遅い環境にいることが多いですから、ここで5MBの画像をダウンロードされたら、もう表示されるまで数秒かかっちゃいます。
せっかくのレスポンシブデザインも、速度が遅いと台無しになっちゃうわけなんです。

だからこそ、デバイスのサイズに応じて、適切なサイズの画像を出し分ける必要があるんです。
これが今日のテーマですね。

srcset属性で賢く画像を切り替える

一番簡単で、多くの場合これで十分な方法がsrcset属性です。
これはもう、現場でめっちゃ使われてますよ。

基本的な書き方はこんな感じです。

<img src="photo-small.jpg" srcset="photo-small.jpg 320w, photo-medium.jpg 768w, photo-large.jpg 1200w" alt="商品の写真">

ここで重要なのがwという単位です。
これは「viewportの幅」を指しています。
つまり「viewport幅が320px以下ならphoto-small.jpgを使って、768pxならphoto-medium.jpgを使って、1200px以上ならphoto-large.jpgを使ってね」って指示してるわけです。

でね、ここで初心者さんがよくやっちゃう勘違いがあるんです。
「viewportが768pxだから、768w のやつが読み込まれる」って思う人、多いんですよ。
実際には、ブラウザが「あ、このデバイスの画面密度は2xだ」って判断したら、次のサイズのやつを読み込んだりするんです。
つまり、ブラウザに任せて最適なやつを選ばせるってイメージです。

もう一つ、sizes属性も組み合わせるとめっちゃ便利です。

<img src="photo-small.jpg" srcset="photo-small.jpg 320w, photo-medium.jpg 768w, photo-large.jpg 1200w" sizes="(max-width: 480px) 100vw, (max-width: 768px) 90vw, 80vw" alt="商品の写真">

sizes属性で「viewport幅480px以下では画像を100vw(viewportの100%)で表示しますよ」って指示できるんです。
こうすると、ブラウザがより正確に最適な画像サイズを計算できるようになります。

実装のコツとしては、まずPC、タブレット、スマホの3段階で画像を用意することをお勧めします。
細かく用意しすぎると、画像管理が大変になっちゃいますからね。

picture要素で本気の出し分け

もうちょっと凝った出し分けをしたい場合は、<picture>要素を使います。
これは「縦長の画像と横長の画像を出し分けたい」とか「フォーマットを変えたい」みたいなときに活躍します。

<picture>
  <source media="(max-width: 480px)" srcset="photo-portrait-small.jpg">
  <source media="(max-width: 768px)" srcset="photo-landscape-medium.jpg">
  <img src="photo-landscape-large.jpg" alt="商品の写真">
</picture>

これだと「スマホ(480px以下)ではこの縦長の画像を、タブレット(768px以下)ではこの横長の画像を」みたいに指定できるんです。
ほんま柔軟ですよ。

僕がよく使う手法が、WebPフォーマットの出し分けです。
WebPはめっちゃ圧縮率がいいんですけど、古いブラウザだと対応してないんです。
だから、こんな風に書きます。

<picture>
  <source srcset="photo.webp" type="image/webp">
  <img src="photo.jpg" alt="商品の写真">
</picture>

こうすると「ブラウザがWebPに対応してたらWebPを、そうじゃなきゃJPGを」ってなるわけです。
JPGで150KBでも、WebPなら80KBくらいに圧縮できることもあります。
これだけで通信量が大幅に減るんです。

実装するときの注意点としては、<source>の順番が大事ってことですね。
ブラウザは上から順番に確認して、最初にマッチしたやつを使うんです。
だから、新しいフォーマット(WebPとか)を上に、ダメ押しの<img>を下に書くんですよ。

あと現場でよく見るのが、srcsetsizes<source>の中で組み合わせるパターンです。
レスポンシブで、なおかつフォーマットも出し分けたいときなんかは、これが必須になります。

まとめ

レスポンシブデザインで画像を出し分けるってのは、単に見た目の問題じゃなくて、ユーザー体験とサイトのパフォーマンスに直結する、めっ