画像のパフォーマンス

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

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

イメージサイズ

画像リソースを使用する際に実行できる最初の最適化は、画像を正しいサイズで表示することです。この場合の「サイズ」とは、画像の「寸法」を指します。他の変数を考慮しない場合、500 ピクセル × 500 ピクセルのコンテナに表示される画像の最適なサイズは 500 ピクセル × 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 のデバイス(ほとんどのデスクトップ ユーザーを含む)は、image-500.jpg 画像をダウンロードします。この画像は、幅 500 ピクセルの外在サイズで表示されます。一方、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 属性は、ブラウザに画像のデコード方法を伝えます。次の 3 つの値があります。

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

JavaScript で HTMLImageElement のインスタンスに対して decode メソッドを使用すると、画像を DOM に挿入できます。

画像デモ

理解度テスト

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

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

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

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

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

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

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

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

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

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