多くの場合、画像はウェブ上で最も重量が多く最も普及しているリソースです。そのため、画像を最適化することで、ウェブサイトのパフォーマンスが大幅に向上します。多くの場合、画像の最適化とは、送信するバイト数を少なくしてネットワーク時間を短縮することを意味しますが、ユーザーのデバイスに合わせて適切なサイズの画像を配信することで、ユーザーに送信されるバイト数を最適化することもできます。
画像をページに追加するには、<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 だけではありません。ページのレイアウトも、もう 1 つの考慮事項です。
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 のデバイスでは image-500.jpg
の画像がダウンロードされます。これにはほとんどのパソコン ユーザーが幅 500 ピクセルの外部サイズで画像を表示するユーザーも含まれます。一方、DPR が 3 のモバイル ユーザーの image-1500.jpg
は、サイズが大きくなる可能性があります。これは、DPR が 3 のデスクトップ デバイスで使用されているものと同じです。
<picture>
<source
media="(min-width: 560px) 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>
要素が追加の <source>
要素を含むように調整され、高 DPR のワイドなデバイスに異なるイメージを使用します。
ビューポートの幅(ピクセル) | 1 DPR | 1.5 DPR | 2 DPR | 3 DPR |
---|---|---|---|---|
320 | 500.jpg | 500.jpg | 500.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: 560px)"
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)で行われる動作とは異なります。Image CDN は、画像を最適化し、ユーザーのデバイスとブラウザに応じて最適な形式で送信するための優れたソリューションです。
バランスを取り、妥当な数の画像候補を生成し、ユーザー エクスペリエンスへの影響を測定することが重要です。画像によって得られる結果は異なる可能性があります。また、各画像に適用される最適化は、ページ内の画像のサイズとユーザーが使用しているデバイスによって異なります。たとえば、e コマースの商品リスティング ページで、全幅のヒーロー画像にはサムネイル画像よりも多くのバリエーションが必要になる場合があります。
遅延読み込み
loading
属性を使用すると、画像がビューポートに表示されたときに、遅延読み込みを行うようにブラウザに指示できます。lazy
の属性値を指定すると、画像がビューポートに入る(または近い)までダウンロードされないようブラウザに指示します。これにより帯域幅が節約され、すでにビューポートにある重要なコンテンツのレンダリングに必要なリソースをブラウザが優先できるようになります。
decoding
decoding
属性は、画像のデコード方法をブラウザに伝えます。値 async
は、画像を非同期でデコードできることをブラウザに伝えます。これにより、他のコンテンツのレンダリング時間が短縮される可能性があります。値 sync
は、画像を他のコンテンツと同時に表示する必要があることをブラウザに伝えます。
デフォルト値の auto
により、ブラウザはユーザーに最適な方法を決定できます。
画像のデモ
理解度テスト
可逆圧縮に対応している画像形式
非可逆圧縮に対応している画像形式
幅記述子(1000w
など)は、srcset
属性で指定された画像候補についてブラウザにどのような情報を伝えていますか?
sizes
属性により、適用先の <img>
要素についてブラウザは何を通知しますか。
<img>
要素の srcset
で指定された候補を表すロジックは、ユーザーの現在のビューポートの寸法に応じて読み込む必要があります。<img>
要素の srcset
属性から読み込まれる画像固有の幅。
次のトピック: 動画のパフォーマンス
画像は、ウェブで最も普及しているメディアタイプかもしれませんが、パフォーマンスに関して念頭に置く必要がある唯一のメディアタイプではありません。動画もウェブ全体で使用される一般的なタイプのメディアであり、独自のパフォーマンスに関する考慮事項が存在します。このコースの次のモジュールでは、動画を最適化する方法と、動画を効率的に読み込む方法について説明します。