ウェブ コミュニティは長年にわたり、ウェブ パフォーマンスの最適化に関する豊富な知識を蓄積してきました。1 つの最適化で多くのサイトのパフォーマンスを改善できる一方で、すべての最適化を一度に行うことは負担になる可能性があります。また、実際には、特定のサイトに適用できる最適化は一部に限られます。
ウェブ パフォーマンスが専門でない限り、サイトに最も大きな影響を与える最適化は明らかではないかもしれません。時間を割くことはおそらくないでしょう。そのため、ユーザーのパフォーマンスを向上させるために、どのような最適化方法を選べば最も効果が高いかを自問することが重要です。
パフォーマンスの最適化について、技術的なメリットのみで判断することはできません。また、特定の最適化を実施できる可能性に影響する人的要因と組織的要因も考慮する必要があります。理論上はパフォーマンスの大幅な向上につながる改善でも、実際には実装する時間やリソースがないデベロッパーがほとんどです。その一方で、ほぼすべての人がすでに実践している、非常に影響力のあるパフォーマンスのベスト プラクティスが存在する可能性もあります。このガイドでは、次のようなウェブ パフォーマンスの最適化について説明します。
- 実世界に影響を与える
- 大半のサイトに関連性があり、適用できる
- ほとんどのデベロッパーにとって実装が現実的である
これらを総合すると、Core Web Vitals の指標を改善するための最も現実的で効果の高い方法を紹介します。ウェブ パフォーマンスについてよく知らない場合や、費用対効果が最も高いものは何か決まっていない場合、まずはこのレポートから始めることをおすすめします。
Interaction to Next Paint(INP)
最新の Core Web Vitals 指標である Interaction to Next Paint(INP)は、改善の余地が最も大きい指標の一つです。ただし、非推奨となった前任者と比較して、「良好」なエクスペリエンスのしきい値を満たしているサイトは大幅に減少しているため、インタラクションの応答性を最適化する方法を初めて学ぶデベロッパーも少なくないかもしれません。まずは知っておくべき手法から、INP を効果的に改善する方法をご紹介します。
1. 長いタスクを分割するために頻繁に Yield する
タスクとは、レンダリング、レイアウト、解析、コンパイル、スクリプトの実行など、ブラウザが行う個別の作業のことです。タスクの実行時間が 50 ミリ秒を超えると、時間のかかるタスクになります。長時間のタスクは、メインスレッドがユーザーの操作に迅速に応答できない可能性があるため、問題があります。
JavaScript では処理をできる限り少なくするよう努める必要がありますが、長いタスクを分割することでメインスレッドをサポートできます。これは、メインスレッドに頻繁に譲渡することで実現できます。これにより、レンダリングの更新やその他のユーザー操作をより早く行うことができます。
Scheduler API を使用すると、優先度システムを使用してタスクをキューに追加できます。具体的には、scheduler.yield() API は長いタスクを分割し、タスクキュー内の位置を放棄することなくインタラクションを処理できるようにします。
長いタスクを分割することで、ユーザーがブロックする重要な作業をブラウザが行える機会が増えます。
2. 不要な JavaScript を避ける
ウェブサイトはかつてないほど多くの JavaScript を配信しています。この傾向は変わっていないようです。送信する JavaScript が多すぎると、タスクがメインスレッドの注意を奪い合う環境が生まれます。これは、特に重要な起動時にウェブサイトの応答性に影響する可能性があります。
ただし、これは解決不可能な問題ではなく、次のようなオプションがあります。
- JavaScript ベースの冗長な実装ではなく、Baseline の幅広く利用可能なウェブ プラットフォーム機能を使用します。
- Chrome DevTools のカバレッジ ツールを使用して、スクリプトで使用されていないコードを探します。起動時に必要なリソースのサイズを小さくすることで、ページがコードの解析とコンパイルに費やす時間を短縮し、スムーズな初期ユーザー エクスペリエンスを提供できます。
- コード分割を使用すると、最初のレンダリングには必要のない、後で使用するコード用の個別のバンドルを作成できます。
- タグ マネージャーを使用している場合は、定期的にタグを最適化してください。未使用のコードを含む古いタグは、タグ マネージャーの JavaScript の使用量を減らすために削除できます。
3. レンダリングの大幅な更新を回避する
JavaScript の実行は、ウェブサイトの応答性に影響する要素の 1 つにすぎません。レンダリングは、それ自体が負荷の高い作業の一種です。大規模なレンダリング更新では、ユーザーの操作に対するウェブサイトの応答がさらに遅くなる可能性があります。
レンダリング作業の最適化は簡単なプロセスではなく、何を達成しようとしているかによって異なります。それでも、レンダリング タスクが長時間タスクにならないようにするために、次のことを行えます。
- JavaScript コードで DOM の読み取りと書き込みを再編成して、強制レイアウトとレイアウト スラッシングを回避します。
- DOM のサイズを小さくする。DOM のサイズとレイアウト作業の負荷は相関しています。レンダラが非常に大きな DOM のレイアウトを更新する必要がある場合、レイアウトの再計算に必要な作業が大幅に増加する可能性があります。
- CSS の制限を使用すると、画面外の DOM コンテンツを遅延レンダリングできます。必ずしも簡単ではありませんが、複雑なレイアウトを含む領域を分離することで、不要なレイアウトとレンダリングの作業を回避できます。
Largest Contentful Paint(LCP)
Largest Contentful Paint(LCP)は、デベロッパーが最も苦労する Core Web Vitals です。Chrome UX レポートのサイトの40% は、優れたユーザー エクスペリエンスに必要な 推奨される LCP のしきい値を満たしていません。Chrome チームでは、LCP を改善する最も効果的な方法として、以下の手法を推奨しています。
1. LCP リソースが HTML ソースから検出可能で、優先度が設定されていることを確認する
Chrome チームは、ウェブでの LCP に関して次のことを確認しています。
- HTTP Archive の 2022 Web Almanac によると、モバイルページの 72% に LCP 要素として画像が含まれています。
- Chrome の実際のユーザーデータを分析したところ、LCP が低いオリジンの大部分は、LCP イメージのダウンロードに p75 LCP 時間の 10%未満を費やしていることがわかりました。
- LCP が低いページの場合、クライアントでの LCP 画像の読み込みは 75 パーセンタイルで 1,290 ミリ秒遅延しています。これは、高速なエクスペリエンスを実現するための予算の半分以上です。
- LCP 要素が画像であるページのうち、画像の 39% は、最初の HTML レスポンスで検出できないソース URL(
<img src="...">
や<link rel="preload" href="...">
など)を持っていました。これらの URL は、ブラウザのプリロード スキャナによってできるだけ早く検出できます。 - Web Almanac によると、
fetchpriority
HTML 属性を利用してリソースの優先順位を高くしている対象ページはわずか 0.03% でした。これには、比較的少ない労力でページの LCP を改善できるページも含まれます。
これらの統計情報は、デベロッパーが LCP 画像のリソース読み込み遅延とリソース読み込み時間の両方を削減できる大きな機会があることを示しています。
リソースの読み込みの遅延が問題となっている場合、CSS や JavaScript が完全に読み込まれてから画像の読み込みが開始されるまで、まだ適切な LCP を達成するには遅すぎる可能性があることを覚えておくことが重要です。さらに、fetchpriority
HTML 属性を使用して優先順位を変更し、より多くの帯域幅を受け取るようにすることで、LCP 画像のリソースの読み込み時間を短縮できます。これにより、読み込みが速くなります。
LCP 要素が画像の場合は、リソースの読み込み遅延を短縮するために、HTML レスポンスで画像の URL を検出できるようにする必要があります。これを実現するためのヒントをいくつかご紹介します。
src
属性またはsrcset
属性を持つ<img>
要素を使用して画像を読み込みます。レンダリングに JavaScript を必要とするdata-src
などの標準以外の属性は使用しないでください。使用すると速度が遅くなります。9% のページで、LCP 画像がdata-src
の背後に隠れています。- クライアントサイド レンダリング(CSR)よりもサーバーサイド レンダリング(SSR)を優先する。SSR では、ページ全体のマークアップ(画像を含む)が HTML ソースに存在することを前提としています。CSR ソリューションでは、画像を検出するには JavaScript を実行する必要があります。
- 外部の CSS ファイルまたは JS ファイルから画像を参照する必要がある場合は、
<link rel="preload">
タグを使って HTML ソースに画像を含めることができます。なお、インライン スタイルで参照される画像は、ブラウザのプリロード スキャナで検出できません。そのため、HTML ソースに画像を見つけても、他のリソースの読み込み時に検出がブロックされる場合があります。このようなケースでは、プリロードが役に立ちます。
さらに、LCP リソースを早期に優先度高く読み込むことで、リソースの読み込み時間を短縮できます。
- LCP 画像の
<img>
タグまたは<link rel="preload">
タグにfetchpriority="high"
属性を追加します。これにより、画像リソースの優先度が上がり、より早く読み込みを開始できるようになります。 - LCP 画像の
<img>
タグからloading="lazy"
属性を削除します。これにより、画像がビューポート内またはビューポートの近くに表示されていることを確認する際に発生する読み込み遅延を回避できます。 - 可能であれば、重要でないリソースを延期します。これらのリソースをドキュメントの最後尾に移動したり、画像や iframe を遅延読み込みしたり、JavaScript を使用して非同期で読み込んだりすることで、LCP 画像などのより重要なリソースをより速く読み込めるようになります。
2. すばやいナビゲーションを目指す
ページの読み込みを待たずに済むのが理想的なユーザー エクスペリエンスです。リソースの検出や優先順位付けなどの LCP の最適化は、LCP 要素の読み込みとレンダリングを待つユーザーの時間を短縮するのに効果的ですが、ネットワーク経由でバイトが読み込まれ、ページにレンダリングされるまでの時間には物理的な限界があります。その上限に達するずっと前に、数ミリ秒でも短縮するために、非常に多くの労力が必要になります。そのため、即時ナビゲーションを実現するには、まったく異なるアプローチをとる必要があります。
即時ナビゲーションでは、ユーザーがページに移動する前に、そのページの読み込みとレンダリングが試行されます。これにより、事前レンダリングされたページをすぐに表示でき、LCP をほぼゼロに抑えることができます。復元と推測の 2 つの方法があります。ユーザーが以前にアクセスしたページに前後に移動すると、そのページはメモリ内キャッシュからすばやく復元され、ユーザーが離れたときとまったく同じ状態で表示されます。ウェブ アプリケーションでは、ユーザーが次に移動するページを予測することもできます。予測が正しければ、ユーザーが移動するまでに次のページが読み込まれ、レンダリングされます。
以前にアクセスしたページは、バックフォワード キャッシュ(bfcache)によって復元できます。使用するには、ページが bfcache の利用条件を満たしていることを確認する必要があります。ページが bfcache の対象にならない一般的な理由は、no-store
キャッシュ ディレクティブで提供されているか、unload
イベント リスナーが設定されているためです。
完全にレンダリングされたページを復元すると、読み込みのパフォーマンスだけでなく、レイアウトの安定性も向上します。bfcache と CLS の改善効果について詳しくは、ページが bfcache の対象となるようにするをご覧ください。
対応ブラウザ
ユーザーが次に訪れるページを事前レンダリングすることも、LCP のパフォーマンスを劇的に向上させる効果的な方法の一つです。事前レンダリングは Speculation Rules API によって実現されます。ただし、これを実現するには、正しいページが事前レンダリングされるようにする必要があります。不正確な推測は、サーバー側とクライアント側の両方でリソースを浪費し、パフォーマンスに悪影響を与える可能性があります。そのため、次のページがどのような内容になるか確信が持てない場合は、プリレンダリングに慎重になる必要があります。疑問がある場合は、アナリティクス データに基づいて、次にアクセスされる可能性が高いページをより積極的にプリレンダリングできます。
3. CDN を使用して TTFB を最適化する
前回の推奨事項では、ユーザーに最適なエクスペリエンスを提供する即時ナビゲーションに焦点を当てましたが、bfcache と推測読み込み手法が適用できない状況もあります。ユーザーがクロスオリジン リンクからサイトにアクセスし、最初の HTML ドキュメント レスポンスが LCP を効果的にブロックしている場合について考えてみましょう。ブラウザは、レスポンスの最初のバイトを受け取るまでサブリソースの読み込みを開始できません。早ければ早いほど、他の作業も早く始められます。
この時間は Time to First Byte(TTFB)と呼ばれます。TTFB を短縮するには、次の方法が最も効果的です。
- コンテンツをできるだけユーザーの地理的位置の近くで配信します。
- そのコンテンツをキャッシュに保存して、近い将来に再度リクエストされた場合にすばやく提供できるようにします。
これらの両方を実現する最善の方法は、CDN を使用することです。CDN は、世界中のエッジサーバーにリソースを分散するため、リソースがワイヤーを介してユーザーに到達する距離を制限できます。また、通常 CDN には、サイトのニーズに合わせて調整できるきめ細かいキャッシュ制御機能があります。
CDN でも HTML ドキュメントの配信とキャッシュ保存が可能ですが、Web Almanac によると、CDN から配信された HTML ドキュメント リクエストの 29% はわずか 29% です。つまり、サイトはさらなる節約の機会を大きく見出しています。
CDN を構成するためのヒントを次に示します。
- 静的 HTML ドキュメントを短時間でもキャッシュに保存します。たとえば、コンテンツが常に新鮮であることは重要ですか?数分遅れても問題ないですか?
- 送信元サーバーで実行されている動的ロジックをエッジに移動できるかどうかを確認する。エッジは最新の CDN の機能である。
エッジから直接コンテンツを提供して、オリジン サーバーにアクセスしなくて済む場合は、パフォーマンスが向上します。オリジンまでリクエストを送信する必要がある場合でも、CDN は通常、より迅速に処理するように最適化されているため、どちらの場合でもメリットがあります。
Cumulative Layout Shift(CLS)
Cumulative Layout Shift(CLS)は、ウェブページの視覚的な安定性の尺度です。CLS は、ほとんどのサイトで高い成果を上げる傾向がある指標ですが、約 4 分の 1 が推奨されるしきい値を満たしていないため、多くのサイトにはユーザー エクスペリエンスを向上させる大きなチャンスが残されています。
1. ページから読み込まれるすべてのコンテンツに明示的なサイズを設定する
レイアウトのずれは、通常、他のコンテンツの読み込みが完了した後に既存のコンテンツが移動したときに発生します。CLS を改善する主な方法は、必要なスペースをできるだけ事前に予約することです。
サイズが指定されていない画像に起因するレイアウト シフトを修正する最善の方法は、width
属性と height
属性、または同等の CSS プロパティを明示的に設定することです。72% のページに、サイズ設定されていない画像が 1 つ以上含まれています。明示的なサイズが指定されていない場合、これらの画像の初期の高さは 0px
になります。このため、画像が読み込まれてブラウザがそのディメンションを検出すると、レイアウトがずれる可能性があります。これは、集合的なウェブにとって大きな機会であり、この機会を活用するために必要な労力は、このガイドで推奨されている他の推奨事項よりも少ないです。
CLS に影響を与えるのは画像だけではありません。レイアウトのずれは、通常はページの初回レンダリング後に読み込まれる他のコンテンツ(サードパーティ広告や埋め込み動画など)が原因で発生することがあります。aspect-ratio
プロパティはこのような場合に役立ちます。これは広く利用可能なベースラインの CSS 機能で、デベロッパーは画像要素だけでなく画像以外の要素にもアスペクト比を明示的に設定できます。これにより、(画面サイズなどに基づいて)動的な width
を設定でき、寸法のある画像の場合とほぼ同じ方法で、ブラウザで適切な高さが自動的に計算されるようになります。
ただし、動的コンテンツの正確なサイズを把握できない場合もあります。正確なサイズがわからない場合でも、レイアウト シフトの重大度を下げることができます。ほとんどの場合、ブラウザが空の要素にデフォルトの高さ 0px
を使用できるようにするよりも、適切な min-height
を設定することをおすすめします。通常、min-height
を使用すると、必要に応じてコンテナを最終的なコンテンツの高さまで拡大できるため、簡単に修正できます。この場合、コンテナの拡大量は許容できるレベルに抑えられます。
2. ページが bfcache の対象であることを確認する
このガイドの前半で説明したように、バックフォワード キャッシュ(bfcache)は、ブラウザの履歴の前のページまたは後のページをメモリ スナップショットから即座に読み込みます。bfcache は、LCP を改善するブラウザレベルの重要なパフォーマンス最適化ですが、レイアウト シフトも完全に排除します。実際、2022 年の bfcache の導入は、その年の CLS の最大の改善につながりました。
にもかかわらず、多くのウェブサイトは bfcache の対象外であるため、この無料のウェブ パフォーマンス向上のメリットを享受できていません。ページに、メモリから復元したくない機密情報が読み込まれる場合を除き、ページが bfcache を使用できる状態であることを確認してください。
サイト所有者は、ページが bfcache の対象となるかどうかを確認し、そうでない場合はその原因を解決する必要があります。Chrome の DevTools に bfcache テスターがあります。また、Not Restored Reasons API を使用して、フィールド内の不適格の理由を検出することもできます。
3. レイアウトを誘発する CSS プロパティを使用するアニメーションと遷移を避ける
レイアウト シフトのもう 1 つの一般的な原因は、要素がアニメーション化される場合です。たとえば、上部または下部からスライドインする Cookie バナーやその他の通知バナーは、多くの場合 CLS の増加につながります。これは、これらのバナーが他のコンテンツを押しのける場合に特に問題になりますが、押しのけない場合でも、アニメーション化すると CLS に影響する可能性があります。
HTTP アーカイブのデータでは、アニメーションとレイアウトのずれを明確に結び付けることはできませんが、レイアウトに影響する可能性がある CSS プロパティをアニメーション化するページでは、全体的なページと比較して「良好」な CLS の確率が 15% 低いことがデータから示されています。一部のプロパティは、他のプロパティよりも CLS の低下と関連付けられています。たとえば、margin
や border
の幅をアニメーション化するページでは、CLS が「低」であり、ページ全体が「低」と評価されるほぼ 2 倍になります。
レイアウトを誘発する CSS プロパティを遷移またはアニメーション化すると、必ずレイアウト シフトが発生します。これらのレイアウト シフトがユーザー操作から 500 ミリ秒以内に発生した場合、CLS に影響します。
一部のデベロッパーにとって驚くべきことに、これは要素が通常のドキュメント フローから外に出た場合でも同様です。たとえば、top
または left
をアニメーション化する絶対配置要素は、他のコンテンツを押し出していない場合でも、レイアウトのずれを生じさせます。ただし、top
または left
をアニメーション化する代わりに、transform:translateX()
または transform:translateY()
をアニメーション化すると、ブラウザはページ レイアウトを更新せず、レイアウト シフトを回避できます。
ブラウザのコンポジタ スレッドで更新できる CSS プロパティのアニメーションを優先することは、長い間パフォーマンスに関するベスト プラクティスとされてきましたが、これは、その処理をメインスレッドから GPU に移すためです。これは一般的なパフォーマンスのベスト プラクティスであるだけでなく、CLS の改善にも役立ちます。
一般的なルールとして、ユーザーのタップやキー入力(hover
は除く)に応じて行わない限り、ブラウザがページ レイアウトを更新する必要がある CSS プロパティをアニメーション化または遷移させないでください。可能な限り、CSS transform
プロパティを使用して遷移とアニメーションを優先してください。
Lighthouse の監査「合成されていないアニメーションは使用しないでください」は、ページで遅くなる可能性のある CSS プロパティがアニメーション化されている場合に警告します。
まとめ
ウェブ上には、ページのパフォーマンスを高めるためのガイダンスが数多く存在するため、その作業は困難に思えるかもしれません。ただし、最も効果的なベスト プラクティスのリストに集中することで、問題に新たな視点から取り組み、ウェブサイトの Core Web Vitals の改善につながる可能性があります。
ここで紹介した最適化以外にも、以下のガイドで詳細をご確認ください。
付録: 変更ログ
このドキュメントの主要な変更は、上位の推奨事項がいつ、なぜ変更されたかを説明するために、ここで追跡されます。
2024 年 10 月
2024 年のアップデート:
- INP
- Core Web Vitals 指標として INP がリリースされたのに合わせて、この指標を FID から INP に切り替え、リストのトップの指標にしました。
- 長いタスクを分割する際に
isInputPending
API を使用することを推奨していた内容を撤回しました。この理由について詳しくは、長時間タスクの最適化に関する記事をご覧ください。
- LCP
- 見つけやすさと優先順位付けの推奨事項を 1 つに統合しました。
- スムーズなナビゲーションを目指した新しい最適化案を追加しました。
2023 年 1 月
推奨事項の最初のリストは次のとおりです。
- LCP
- LCP リソースが HTML ソースから検出可能であることを確認する
- LCP リソースが優先されていることを確認する
- CDN を使用してドキュメントとリソースの TTFB を最適化する
- CLS
- ページから読み込まれるコンテンツに明示的なサイズを設定する
- ページが bfcache の対象であることを確認する
- レイアウトを誘発する CSS プロパティを使用するアニメーションと遷移を避ける
- FID
- 長いタスクを回避するか、分割する
- 不要な JavaScript を避ける
- レンダリングの大幅な更新を回避する
また、こちらの 2023 年 Google I/O プレゼンテーションで概要の動画もご覧ください。