画像のパフォーマンス

画像は、ウェブ上で最も重く、最も一般的なリソースです。そのため、画像を最適化すると、ウェブサイトのパフォーマンスを大幅に改善できます。ほとんどの場合、画像を最適化するとは、送信するバイト数を減らしてネットワーク時間を短縮することを意味しますが、ユーザーのデバイスに適切なサイズの画像を提供することで、ユーザーに送信するバイト数を最適化することもできます。

画像は、<img> 要素または <picture> 要素、または CSS の background-image プロパティを使用してページに追加できます。

イメージサイズ

画像リソースを使用する際に実行できる最初の最適化は、画像を正しいサイズで表示することです。ここでいう「サイズ」とは、画像の「寸法」を指します。他の変数を考慮しない場合、500 ピクセル x 500 ピクセルのコンテナに表示される画像の最適なサイズは 500 ピクセル x 500 ピクセルになります。たとえば、1, 000 ピクセルの正方形の画像を使用すると、画像は必要なサイズの 2 倍になります。

ただし、適切な画像サイズの選択には多くの変数が関係するため、すべてのケースで適切な画像サイズを選択するのは非常に複雑な作業になります。2010 年に iPhone 4 がリリースされたとき、画面解像度(640x960)は iPhone 3(320x480)の 2 倍でした。しかし、iPhone 4 の画面の物理サイズは iPhone 3 とほぼ同じでした。

すべてを高解像度で表示すると、テキストや画像が大幅に小さくなります(以前のサイズの半分になります)。代わりに、1 ピクセルが 2 つのデバイス ピクセルになりました。これをデバイスのピクセル比(DPR)と呼びます。iPhone 4 以降にリリースされた多くの iPhone モデルの DPR は 2 でした。

前の例に戻ると、デバイスの DPR が 2 で、画像が 500 ピクセル x 500 ピクセルのコンテナに表示される場合、最適なサイズは 1,000 ピクセルの正方形の画像(固有サイズ)になります。同様に、デバイスの DPR が 3 の場合、1,500 ピクセルの正方形の画像が最適なサイズになります。

srcset

<img> 要素は srcset 属性をサポートしています。この属性を使用すると、ブラウザが使用する可能性のある画像ソースのリストを指定できます。指定する各画像ソースには、画像 URL と幅またはピクセル密度の記述子を含める必要があります。

<img
  alt="An image"
  width="500"
  height="500"
  src="/image-500.jpg"
  srcset="/image-500.jpg 1x, /image-1000.jpg 2x, /image-1500.jpg 3x"
>

上記の HTML スニペットでは、ピクセル密度記述子を使用して、DPR が 1 のデバイスでは image-500.png、DPR が 2 のデバイスでは image-1000.jpg、DPR が 3 のデバイスでは image-1500.jpg を使用するようブラウザにヒントを与えています。

これらはすべて明確な基準のように見えますが、特定のページに最適な画像を選択するうえで、画面の DPR だけが考慮されるわけではありません。ページのレイアウトも考慮事項の一つです。

sizes

前の解決策は、すべてのビューポートで同じ CSS ピクセル サイズで画像を表示する場合にのみ機能します。多くの場合、ページのレイアウト(およびコンテナのサイズ)はユーザーのデバイスによって異なります。

sizes 属性を使用すると、ソースサイズのセットを指定できます。各ソースサイズは、メディア条件と値で構成されます。sizes 属性は、画像の表示サイズを CSS ピクセル単位で指定します。srcset 幅記述子と組み合わせることで、ブラウザはユーザーのデバイスに最適な画像ソースを選択できます。

<img
  alt="An image"
  width="500"
  height="500"
  src="/image-500.jpg"
  srcset="/image-500.jpg 500w, /image-1000.jpg 1000w, /image-1500.jpg 1500w"
  sizes="(min-width: 768px) 500px, 100vw"
>

上記の HTML スニペットでは、srcset 属性で、ブラウザが選択できる画像候補のリストをカンマ区切りで指定しています。リスト内の各候補は、画像の URL と、画像の固有の幅を示す構文で構成されます。画像の固有サイズは、その寸法です。たとえば、1000w の記述子は、画像の固有の幅が 1, 000 ピクセルであることを示します。

この情報を使用して、ブラウザは sizes 属性のメディア条件を評価します。この場合、デバイスのビューポートの幅が 768 ピクセルを超える場合は、画像の幅を 500 ピクセルで表示するように指示されます。小さいデバイスでは、画像は 100vw(ビューポートの幅全体)で表示されます。

ブラウザは、この情報を srcset 画像ソースのリストと組み合わせて、最適な画像を見つけることができます。たとえば、画面の幅が 320 ピクセルで DPR が 3 のモバイル デバイスでユーザーが閲覧している場合、画像は 320 CSS pixels x 3 DPR = 960 device pixels で表示されます。この例では、最も近いサイズの画像は image-1000.jpg で、固有の幅は 1, 000 ピクセル(1000w)です。

ファイル形式

ブラウザは、さまざまな画像ファイル形式をサポートしています。WebPAVIF などの最新の画像形式は、PNG や JPEG よりも圧縮率が高く、画像ファイルのサイズを小さくしてダウンロード時間を短縮できます。最新の形式で画像を提供することで、リソースの読み込み時間を短縮できます。これにより、Largest Contentful Paint(LCP)が短縮される可能性があります。

WebP は、最新のすべてのブラウザで動作する広くサポートされている形式です。WebP は JPEG、PNG、GIF よりも圧縮率が高く、非可逆圧縮可逆圧縮の両方に対応しています。WebP は、非可逆圧縮を使用している場合でもアルファ チャンネルの透明度をサポートしています。これは JPEG コーデックにはない機能です。

AVIF は新しい画像形式であり、WebP ほど幅広くサポートされてはいませんが、ブラウザ全体でかなり適切にサポートされています。AVIF は非可逆圧縮と可逆圧縮の両方をサポートしており、テストでは、JPEG と比較して 50% 以上の節約が実現される場合があることが示されています。AVIF は、広色域(WCG)ハイ ダイナミック レンジ(HDR)の機能も提供します。

圧縮

画像に関しては、次の 2 種類の圧縮があります。

  1. ロッシー圧縮
  2. ロスレス圧縮

不可逆圧縮は、量子化によって画像の精度を低下させることで機能します。また、クロマ サブサンプリングを使用して追加の色情報を破棄することもできます。非可逆圧縮は、ノイズや色が多く、類似したコンテンツを含む高密度の画像(通常は写真や画像)で最も効果的です。これは、このような詳細な画像では、不可逆圧縮によって生成されるアーティファクトが目立ちにくいからです。ただし、線画、同様に鮮明なディテール、テキストなど、シャープなエッジを含む画像では、不可逆圧縮の効果が低下する可能性があります。非可逆圧縮は、JPEG、WebP、AVIF 画像に適用できます。

ロスレス圧縮では、データ損失なしで画像を圧縮することでファイルサイズを縮小します。ロスレス圧縮では、ピクセルが隣接するピクセルとの差に基づいて記述されます。GIF、PNG、WebP、AVIF の画像形式では、可逆圧縮が使用されます。

画像は、SquooshImageOptim、または画像最適化サービスを使用して圧縮できます。圧縮する際に、すべてのケースに適した普遍的な設定はありません。推奨されるアプローチは、画質とファイルサイズの適切な妥協点が見つかるまで、さまざまな圧縮レベルを試すことです。高度な画像最適化サービスの中には、この処理を自動的に行うものもありますが、すべてのユーザーにとって経済的に実現可能とは限りません。

<picture> 要素

<picture> 要素を使用すると、複数の画像候補をより柔軟に指定できます。

<picture>
  <source type="image/avif" srcset="image.avif">
  <source type="image/webp" srcset="image.webp">
  <img
    alt="An image"
    width="500"
    height="500"
    src="/image.jpg"
  >
</picture>

<picture> 要素内で <source> 要素を使用すると、AVIF 画像と WebP 画像のサポートを追加できます。ブラウザが最新の形式をサポートしていない場合は、互換性の高い従来の画像形式にフォールバックします。このアプローチでは、ブラウザは一致する最初の <source> 要素を選択します。その形式で画像をレンダリングできる場合は、その画像を使用します。それ以外の場合は、ブラウザは次に指定された <source> 要素に移動します。上記の HTML スニペットでは、AVIF 形式が WebP 形式よりも優先され、AVIF と WebP のどちらもサポートされていない場合は JPEG 形式にフォールバックします。

<picture> 要素には、その中にネストされた <img> 要素が必要です。altwidthheight の各属性は <img> で定義され、選択された <source> に関係なく使用されます。

<source> 要素は、mediasrcsetsizes の各属性もサポートしています。前の <img> の例と同様に、これらはさまざまなビューポートで選択する画像をブラウザに指示します。

<picture>
  <source
    media="(min-resolution: 1.5x)"
    srcset="/image-1000.jpg 1000w, /image-1500.jpg 1500w"
    sizes="(min-width: 768px) 500px, 100vw"
  >
  <img
    alt="An image"
    width="500"
    height="500"
    src="/image-500.jpg"
  >
</picture>

media 属性はメディア条件を受け取ります。上記の例では、デバイスの DPR がメディア条件として使用されています。DPR が 1.5 以上のデバイスは、最初の <source> 要素を使用します。<source> 要素は、ビューポートの幅が 768 ピクセルを超えるデバイスでは、選択された画像候補が 500 ピクセルの幅で表示されることをブラウザに伝えます。小さいデバイスでは、ビューポートの幅全体を占めます。media 属性と srcset 属性を組み合わせることで、使用する画像をより細かく制御できます。

次の表に、いくつかのビューポート幅とデバイス ピクセル比率を評価した結果を示します。

ビューポートの幅(ピクセル) 1 DPR 1.5 DPR 2 DPR 3 DPR
320 500.jpg 500.jpg 500.jpg 1000.jpg
480 500.jpg 500.jpg 1000.jpg 1500.jpg
560 500.jpg 1000.jpg 1000.jpg 1500.jpg
1024 500.jpg 1000.jpg 1000.jpg 1500.jpg
1920 500.jpg 1000.jpg 1000.jpg 1500.jpg

DPR が 1 のデバイス(ほとんどのデスクトップ ユーザーを含む)は、幅 500 ピクセルの外在的なサイズで画像を表示するため、image-500.jpg 画像をダウンロードします。一方、DPR が 3 のモバイル ユーザーは、DPR が 3 のデスクトップ デバイスで使用されているのと同じ画像である、より大きな image-1500.jpg をダウンロードします。

<picture>
  <source
    media="(min-width: 561px) and (min-resolution: 1.5x)"
    srcset="/image-1000.jpg 1000w, /image-1500.jpg 1500w"
    sizes="(min-width: 768px) 500px, 100vw"
  >
  <source
    media="(max-width: 560px) and (min-resolution: 1.5x)"
    srcset="/image-1000-sm.jpg 1000w, /image-1500-sm.jpg 1500w"
    sizes="(min-width: 768px) 500px, 100vw"
  >
  <img
    alt="An image"
    width="500"
    height="500"
    src="/image-500.jpg"
  >
</picture>

この例では、<picture> 要素が調整され、DPR が高いワイド デバイスで異なる画像を使用するための追加の <source> 要素が含まれています。

ビューポートの幅(ピクセル) 1 DPR 1.5 DPR 2 DPR 3 DPR
320 500.jpg 500.jpg 1000-sm.jpg 1000-sm.jpg
480 500.jpg 500.jpg 1000-sm.jpg 1500-sm.jpg
560 500.jpg 1000-sm.jpg 1000-sm.jpg 1500-sm.jpg
1024 500.jpg 1000.jpg 1000.jpg 1500.jpg
1920 500.jpg 1000.jpg 1000.jpg 1500.jpg

この追加のクエリを使用すると、image-1000-sm.jpgimage-1500-sm.jpg が小さなビューポートに表示されていることがわかります。この追加情報により、そのサイズと密度では圧縮アーティファクトが目立たず、デスクトップ デバイスの画質も損なわれないため、画像をさらに圧縮できます。

また、srcset 属性と media 属性を調整することで、小さなビューポートに大きな画像が表示されないようにすることもできます。

<picture>
  <source
    media="(min-width: 561px)"
    srcset="/image-500.jpg, /image-1000.jpg 2x, /image-1500.jpg 3x"
  >
  <source
    media="(max-width: 560px)"
    srcset="/image-500.jpg 1x, /image-1000.jpg 2x"
  >
  <img
    alt="An image"
    width="500"
    height="500"
    src="/image-500.jpg"
  >
</picture>

上記の HTML スニペットでは、デバイスのピクセル比率記述子を使用するために幅記述子が削除されています。モバイル デバイスで配信される画像は、DPR が 3 のデバイスでも /image-500.jpg または /image-1000.jpg に制限されます。

複雑さの管理方法

レスポンシブ画像を扱う場合、各画像にさまざまなサイズ バリエーションと形式があることがあります。上記の例では、各サイズのバリエーションが使用されていますが、AVIF と WebP は除外されています。バリエーションの数はどのくらいが適切ですか?多くのエンジニアリングの問題と同様に、答えは「場合による」ということになります。

最適な画像を配信するために、できるだけ多くのバリエーションを用意したくなるかもしれませんが、画像バリエーションを追加するたびにコストがかかり、ブラウザ キャッシュの効率的な使用が妨げられます。バリエーションが 1 つだけの場合、すべてのユーザーに同じ画像が配信されるため、非常に効率的にキャッシュに保存できます。

一方、バリエーションが多い場合は、バリエーションごとに別のキャッシュ エントリが必要になります。バリアントのキャッシュ エントリの有効期限が切れ、オリジン サーバーから画像を再度取得する必要がある場合、サーバー費用が増加し、パフォーマンスが低下する可能性があります。

これ以外にも、HTML ドキュメントのサイズはバリエーションごとに大きくなります。画像ごとに数キロバイトの HTML を送信することになる可能性があります。

Accept リクエスト ヘッダーに基づいて画像を提供する

Accept HTTP リクエスト ヘッダーは、ユーザーのブラウザが理解できるコンテンツ タイプをサーバーに通知します。この情報は、サーバーが HTML レスポンスに余分なバイトを追加することなく、最適な画像形式を提供するために使用できます。

if (request.headers.accept) {
  if (request.headers.accept.includes('image/avif')) {
    return reply.from('image.avif');
  } else if (request.headers.accept.includes('image/webp')) {
    return reply.from('image.webp');
  }
}

return reply.from('image.jpg');

上記の HTML スニペットは、最適な画像形式を選択して配信するためにサーバーの JavaScript バックエンドに追加できるコードの簡略版です。リクエストの Accept ヘッダーに image/avif が含まれている場合、AVIF 画像が配信されます。それ以外の場合、Accept ヘッダーに image/webp が含まれていれば、WebP 画像が配信されます。どちらの条件にも該当しない場合は、JPEG 画像が配信されます。

ほぼすべてのタイプのウェブサーバーで、Accept リクエスト ヘッダーの内容に基づいてレスポンスを変更できます。たとえば、mod_rewrite を使用して、Accept ヘッダーに基づいて Apache サーバーで画像リクエストを書き換えることができます。

これは、画像コンテンツ配信ネットワーク(CDN)で見られる動作と似ています。画像 CDN は、画像を最適化し、ユーザーのデバイスとブラウザに基づいて最適な形式を送信するための優れたソリューションです。

重要なのは、バランスを見つけ、妥当な数の画像候補を生成し、ユーザー エクスペリエンスへの影響を測定することです。画像が異なると結果も異なり、各画像に適用される最適化は、ページ内の画像のサイズとユーザーが使用しているデバイスによって異なります。たとえば、全幅のヒーロー画像では、e コマースの商品リスティング ページのサムネイル画像よりも多くのバリエーションが必要になる場合があります。

遅延読み込み

loading 属性を使用すると、ビューポートに表示されたときに画像を遅延読み込みするようにブラウザに指示できます。属性値 lazy は、画像がビューポート内(またはその近く)に表示されるまでダウンロードしないようブラウザに指示します。これにより帯域幅が節約され、ブラウザはビューポートにすでに表示されている重要なコンテンツをレンダリングするために必要なリソースを優先できます。

decoding

decoding 属性は、ブラウザが画像をデコードする方法を指定します。値 async は、画像を非同期でデコードできることをブラウザに伝え、他のコンテンツのレンダリング時間を短縮できる可能性があります。sync の値は、画像を他のコンテンツと同時に表示するようブラウザに指示します。auto のデフォルト値を使用すると、ブラウザがユーザーにとって最適なものを判断できます。

画像デモ

理解度テスト

可逆圧縮に対応している画像形式はどれですか?

.GIF のいずれかの形式で保存します。
正解です。
JPEG。
もう一度お試しください。
PNG など
正解です。
WebP。
正解です。
AVIF。
正解です。

非可逆圧縮をサポートしている画像形式はどれですか?

.GIF のいずれかの形式で保存します。
もう一度お試しください。GIF 形式は 256 色の限られたパレットしかサポートしていませんが、GIF に変換する前に非可逆エンコードを行う必要があります。
JPEG。
正解です。
PNG など
もう一度お試しください。
WebP。
正解です。
AVIF。
正解です。

幅記述子(1000w など)は、srcset 属性で指定された画像候補について、ブラウザに何を伝えますか?

画像の外部幅。つまり、ページにスタイルが適用された後のレイアウトにおける画像のサイズ
もう一度お試しください。
画像の固有の幅。つまり、画像自体の寸法です。
正解です。

sizes 属性は、適用先の <img> 要素についてブラウザに何を伝えますか?

ユーザーの現在のビューポートのサイズに基づいて、<img> 要素の srcset で指定されたどの候補を読み込むべきかを表すロジック。
正解です。
<img> 要素の srcset 属性から読み込まれる画像の固有の幅。
もう一度お試しください。

次へ: 動画のパフォーマンス

画像はウェブで最も一般的なメディアタイプですが、パフォーマンスを考慮するうえで、画像だけを念頭に置けばよいというわけではありません。動画はウェブ全体でよく使用されるもう 1 つの一般的なメディアタイプであり、独自のパフォーマンスに関する考慮事項があります。このコースの次のモジュールでは、動画の最適化と効率的な読み込みに関する手法について説明します。