画像は、ウェブ上で最も重く、最も一般的なリソースです。そのため、画像を最適化すると、ウェブサイトのパフォーマンスを大幅に改善できます。ほとんどの場合、画像を最適化するとは、送信するバイト数を減らしてネットワーク時間を短縮することを意味しますが、ユーザーのデバイスに適切なサイズの画像を提供することで、ユーザーに送信するバイト数を最適化することもできます。
画像は、<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
)です。
ファイル形式
ブラウザは、さまざまな画像ファイル形式をサポートしています。WebP や AVIF などの最新の画像形式は、PNG や JPEG よりも圧縮率が高く、画像ファイルのサイズを小さくしてダウンロード時間を短縮できます。最新の形式で画像を提供することで、リソースの読み込み時間を短縮できます。これにより、Largest Contentful Paint(LCP)が短縮される可能性があります。
WebP は、最新のすべてのブラウザで動作する広くサポートされている形式です。WebP は JPEG、PNG、GIF よりも圧縮率が高く、非可逆圧縮と可逆圧縮の両方に対応しています。WebP は、非可逆圧縮を使用している場合でもアルファ チャンネルの透明度をサポートしています。これは JPEG コーデックにはない機能です。
AVIF は新しい画像形式であり、WebP ほど幅広くサポートされてはいませんが、ブラウザ全体でかなり適切にサポートされています。AVIF は非可逆圧縮と可逆圧縮の両方をサポートしており、テストでは、JPEG と比較して 50% 以上の節約が実現される場合があることが示されています。AVIF は、広色域(WCG)とハイ ダイナミック レンジ(HDR)の機能も提供します。
圧縮
画像に関しては、次の 2 種類の圧縮があります。
不可逆圧縮は、量子化によって画像の精度を低下させることで機能します。また、クロマ サブサンプリングを使用して追加の色情報を破棄することもできます。非可逆圧縮は、ノイズや色が多く、類似したコンテンツを含む高密度の画像(通常は写真や画像)で最も効果的です。これは、このような詳細な画像では、不可逆圧縮によって生成されるアーティファクトが目立ちにくいからです。ただし、線画、同様に鮮明なディテール、テキストなど、シャープなエッジを含む画像では、不可逆圧縮の効果が低下する可能性があります。非可逆圧縮は、JPEG、WebP、AVIF 画像に適用できます。
ロスレス圧縮では、データ損失なしで画像を圧縮することでファイルサイズを縮小します。ロスレス圧縮では、ピクセルが隣接するピクセルとの差に基づいて記述されます。GIF、PNG、WebP、AVIF の画像形式では、可逆圧縮が使用されます。
画像は、Squoosh、ImageOptim、または画像最適化サービスを使用して圧縮できます。圧縮する際に、すべてのケースに適した普遍的な設定はありません。推奨されるアプローチは、画質とファイルサイズの適切な妥協点が見つかるまで、さまざまな圧縮レベルを試すことです。高度な画像最適化サービスの中には、この処理を自動的に行うものもありますが、すべてのユーザーにとって経済的に実現可能とは限りません。
<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>
要素が必要です。alt
、width
、height
の各属性は <img>
で定義され、選択された <source>
に関係なく使用されます。
<source>
要素は、media
、srcset
、sizes
の各属性もサポートしています。前の <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.jpg
と image-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
のデフォルト値を使用すると、ブラウザがユーザーにとって最適なものを判断できます。
画像デモ
理解度テスト
可逆圧縮に対応している画像形式はどれですか?
非可逆圧縮をサポートしている画像形式はどれですか?
幅記述子(1000w
など)は、srcset
属性で指定された画像候補について、ブラウザに何を伝えますか?
sizes
属性は、適用先の <img>
要素についてブラウザに何を伝えますか?
<img>
要素の srcset
で指定されたどの候補を読み込むべきかを表すロジック。<img>
要素の srcset
属性から読み込まれる画像の固有の幅。次へ: 動画のパフォーマンス
画像はウェブで最も一般的なメディアタイプですが、パフォーマンスを考慮するうえで、画像だけを念頭に置けばよいというわけではありません。動画はウェブ全体でよく使用されるもう 1 つの一般的なメディアタイプであり、独自のパフォーマンスに関する考慮事項があります。このコースの次のモジュールでは、動画の最適化と効率的な読み込みに関する手法について説明します。