Web における画像ロードベストプラクティス
Picture perfect images with the modern <img>
element - Stack Overflow Blog という記事によくまとまっている。
また、関連して Priority Hints の fetchpriority
属性とあわせて紹介する。
導入として、Web における画像のペイロードは大きくなる一方で、Core Web Vitals にも大きく影響している。
-
Largest Contentful Paint のために、
<link rel="preload">
やfetchpriority
属性でヒーロー画像のリクエストを早めたり、srcset
属性や<source>
要素で適切なフォーマットの画像をロードし、画面外の画像はloading
属性でロードを遅らせる -
Cumulative Layout Shift のために、画像の縦横サイズを
width
とheight
属性で指定したり、CSS のaspect-ratio
プロパティで画角を指定する - First Input Delay のために、クリティカルレンダリングパスに含まれるリソースのロードを邪魔する画像を使わない
Google 検索へのページ エクスペリエンスの導入時期 の通り、Core Web Vitals の評価は Google 検索ランクにも影響する。
計測には Lighthouse を使う。Chrome の DevTools にもバンドルされている他、Page Speed Insights や WebPageTest、CI からでも利用できる。
Cumulative Layout Shift
<img>
要素の基本として、 src
属性でファイルの URL を指定するだけでなく、 alt
属性で代替テキストを、 width
属性と height
属性で縦横サイズを指定することでレイアウトを減らす。
<img
src="keyboard.jpg"
alt="A beautiful pink keyboard."
width="400"
height="400">
width
属性と height
属性を指定することでページレイアウトに占めるサイズが固定され、レイアウトシフトを軽減できる。その重要性については Setting Height And Width On Images Is Important Again でも言及されている。
Largest Contentful Paint
画像は Web ページにおける大部分を占める傾向にあり、LCP に該当する場合も多い。よって、ImageOptim や Squoosh で最適化しペイロードサイズを減らすだけでなく、適切な画像を <img>
要素でロードする工夫を凝らす必要がある。
<img
src="keyboard-800w.jpg"
alt="A beautiful pink keyboard."
width="400"
height="400"
srcset="
keyboard-400w.jpg 400w,
keyboard-800w.jpg 800w"
sizes="(max-width: 640px) 400px, 800px">
srcset
属性によって、ビューポートのサイズやピクセル密度に応じてロードするファイルを指定する。この例では、400px までは keyboard-400w.jpg
を、800px までは keyboard-800w.jpg
を、それ以外は src
属性で指定されている keyboard-800w.jpg
をロードする。
sizes
属性によって、メディアクエリに応じた画像のサイズを指定する。この例では、ビューポートのサイズが 640px までは 400px で、640px より大きい場合は 800px で表示される。
また、昨今ではより圧縮効率の良い WebP や AVIF といった新しい画像フォーマットもあるが、<picture>
要素と <source>
要素はそれらを選択的にロードすることを実現する。
<picture>
<source srcset="keyboard.avif" type="image/avif">
<source srcset="keyboard.webp" type="image/webp">
<source srcset="keyboard.jpg" type="image/jpeg">
<img src="keyboard.jpg" alt="Omg a keyboard">
</picture>
<source>
要素で指定された画像のうちどれをロードするかは、ブラウザの HTTP Accept
ヘッダ に依存する。
Web ページの HTML ドキュメントが返却されてパースしている際に、リソースを優先的にロードしたい場合には <link rel="preload">
を使う。LCP が画像の場合などでロードを優先させたい場合は、<link rel="preload" as="image" href="keyboard.webp" type="image/webp">
のように指定することで優先的にリクエストを促すことができる。また、imagesrcset
属性や imagesizes
属性を使うことで、レスポンシブな指定もできる。
<link
rel="preload"
as="image"
href="keyboard.jpg"
imagesrcset="
poster_400px.jpg 400w,
poster_800px.jpg 800w,
poster_1600px.jpg 1600w"
imagesizes="50vw">
認知的なパフォーマンス改善として、画像がロードされるまでのプレースホルダとして軽量な代替画像を <img>
要素の背景画像として指定しておく手法がある。ここで decoding
属性に async
を指定しておくことで、ブラウザのメインスレッドを専有しないよう画像のデコード処理を非同期に実行させる。そして非同期に実行している間、プレースホルダとして指定した背景画像が表示される。
<img
src="donut-800w.jpg"
alt="A delicious donut"
width="400"
height="400"
srcset="
donut-400w.jpg 400w,
donut-800w.jpg 800w"
sizes="(max-width: 640px) 400px, 800px"
loading="lazy"
decoding="async"
style="
background-size: cover;
background-image: url(data:image/svg+xml;base64,[svg text]);">
First Input Delay
クリティカルレンダリングパスが処理されてようやくブラウザがアイドル状態になるため、ペイロードサイズの大きい画像も必然的に大きく影響してくる。通常、画像は積極的にダウンロードされるためページ全体の画像をダウンロードするコストも小さくない。ここで loading
属性を使うことで、ブラウザネイティブの遅延ロードを促すことができる。
<img
src="donut.jpg"
alt="A delicious pink donut."
loading="lazy"
width="400"
height="400">
loading
属性に lazy
が指定されると、スクリーン外に配置されている画像をロードしなくなる。これによってブラウザは初期表示に必要な画像のロードに集中できるため、クリティカルレンダリングパスの構築も阻害しない。また、これは srcset
属性が指定されていても同等に機能する。
ここまでは <img>
要素に着目した話だったが、Web ページに含まれるサブリソースは画像だけではない。外部リソースを要求する HTML 要素は <img>
と <iframe>
と <link>
と <script>
要素があり、これらを総合した上でどのような優先度でリソースを要求するかの優先度を指定するのが Priority Hints である。
ここで表現している「リソース」は HTML 上で指定するものに限らず、Fetch Standard で整理される Web におけるリソースに該当するものである。つまり fetch()
などにも Priority Hints を指定するオプションが存在するが、この記事の說明においては割愛する。
リソースの投機的なロードという需要に対しては、Resource Hints が仕様として存在するが、Priority Hints はそれを補強することになる。先の HTML 要素に対して fetchpriority
属性を指定することで、どのリソースが優先的にロードされるかを示唆する。
例えば、クリティカルレンダリングパスに含まれる <head>
要素内の <link rel="stylesheet">
などは、暗黙的に最も高い優先度でリクエストされるが、リソースを取得する <link>
要素、<script>
要素、<img>
要素、<iframe>
要素は、fetchpriority
属性で互いの優先度関係を明示できる。つまり、<link rel="preload" fetchpriority="low">
や <script defer fetchpriority="high">
のような指定も必要に応じて可能だ。