2023 年に Core Web Vitals のパフォーマンスを向上させる最も効果的な方法であると Chrome DevRel チームが考えているベスト プラクティスをまとめています。
長年にわたり、Google はウェブ デベロッパーにパフォーマンスを向上させるための多くの提案を行ってきました。
多くのサイトにおいて、これらの最適化案はどれも単独でもパフォーマンスの向上につながる可能性がありますが、すべての最適化案が多大なものであることは確かであり、現実的には、1 人または 1 つのサイトがそのすべてに従うことは不可能です。
ウェブ パフォーマンスが日常業務でない限り、どの最適化案がサイトに最も大きなプラスの影響を与えるかは明らかではありません。たとえば、重要な CSS を実装すると読み込みのパフォーマンスが向上するとお読みになったことがあるかもしれません。また、画像の最適化が重要であることも耳にしたことがあるでしょう。しかし、両方に取り組む時間がない場合、どちらを選ぶか決めましょう。
Chrome チームでは、この 1 年間、ユーザーのパフォーマンスを改善するためにデベロッパーに提示できる最も重要な推奨事項は何ですか。
この質問に適切に答えるには、特定の推奨事項の技術的なメリットだけでなく、デベロッパーがそれらの推奨事項を実際に採用できる可能性に影響を与える人的要因と組織的要因も考慮する必要があります。言い換えれば、提案の中には理論的には大きな影響を与えるものもありますが、実際にそれを実装するための時間やリソースを持つサイトはほとんどありません。同様に、一部の推奨事項は重要ですが、ほとんどのウェブサイトはすでにこれらのプラクティスに従っています。
要するに、ウェブ パフォーマンスに関する重要な推奨事項のリストでは、以下の点を重視したいと考えました。
- 現実世界に最大の効果をもたらすと考えられる最適化案
- ほとんどのサイトに適している最適化案
- ほとんどのデベロッパーにとって現実的な推奨事項
Google は過去 1 年間、Google が提示するパフォーマンスに関する推奨事項をすべて監査し、上記の 3 つの基準に照らして各最適化案を(定性的と定量的に)評価してきました。
この投稿では、Core Web Vitals の各指標について、パフォーマンスを改善するための主な推奨事項について概説します。ウェブ パフォーマンスを初めて使用する場合や、費用対効果を最大化する方法を判断したい場合は、以下の推奨事項から始めることをおすすめします。
Largest Contentful Paint(LCP)
最初の推奨事項は、読み込みパフォーマンスの指標である Largest Contentful Paint(LCP)です。Core Web Vitals の 3 つの指標のうち、LCP は最も多くのサイトが最も問題を抱えているサイトです。現在ウェブの全サイトの約半分が推奨しきい値を満たしているので、まずは LCP から始めましょう。
LCP リソースが HTML ソースから検出可能であることを確認する
HTTP Archive の 2022 Web Almanac によると、モバイルページの 72% に LCP 要素として画像があります。つまり、ほとんどのサイトで LCP を最適化するには、画像をすばやく読み込めるようにする必要があります。
多くのデベロッパーにとって明白でないのは、画像の読み込みにかかる時間は課題の一部にすぎないということです。もう 1 つの重要な要素は、画像の読み込みを開始する前の時間です。HTTP アーカイブ データから、実際に多くのサイトが操作される原因になります。
実際、LCP 要素が画像であるページのうち、39% の画像には、HTML ドキュメントのソースから検出できないソース URL がありました。つまり、これらの URL は標準の HTML 属性(<img src="...">
や <link rel="preload" href="...">
など)には含まれていなかったので、ブラウザですばやく検出して読み込みを開始できていました。
CSS ファイルまたは JavaScript ファイルが完全にダウンロード、解析、処理されるのを待ってから画像の読み込みを開始する必要がある場合は、すでに手遅れになっている可能性があります。
原則として、LCP 要素が画像の場合、画像の URL は常に HTML ソースから検出できる必要があります。これを行うためのヒントをいくつかご紹介します。
src
属性またはsrcset
属性を指定した<img>
要素を使用して画像を読み込みます。data-src
など、レンダリングに JavaScript を必要とする標準以外の属性は使用しないでください。使用すると常に速度が低下します。9% のページで LCP 画像がdata-src
の背後に隠れています。クライアントサイド レンダリング(CSR)よりもサーバーサイド レンダリング(SSR)を優先します。SSR は、ページ全体のマークアップ(画像を含む)が HTML ソースに存在することを意味します。CSR ソリューションでは、画像を検出する前に JavaScript を実行する必要があります。
外部の CSS または JS ファイルから画像を参照する必要がある場合は、
<link rel="preload">
タグを使って HTML ソースに画像を含めることができます。インライン スタイルで参照されている画像は、ブラウザのプリロード スキャナでは検出できません。そのため、たとえ HTML ソースで見つかった場合でも、他のリソースの読み込み時に検出がブロックされることがあります。そのような場合は、プリロードが役立ちます。
LCP イメージに検出可能性の問題があるかどうかを把握できるように、Lighthouse ではバージョン 10.0 で新しい監査をリリースします(2023 年 1 月提供予定)。
LCP リソースを HTML ソースから検出可能にすることで、測定可能な改善につながるだけでなく、次に推奨するリソースに優先順位を付ける機会も増えます。
LCP リソースが優先されます
LCP リソースが早期に読み込みを開始できるようにするための重要な最初のステップは、HTML ソースから LCP リソースを検出できるようにすることですが、もう 1 つの重要なステップは、そのリソースの読み込みを優先し、重要性の低い他の多数のリソースの背後にキューに入れないようにすることです。
たとえば、標準の <img>
タグを使用して LCP 画像が HTML ソースに存在していても、ページのドキュメントの <head>
で、その <img>
タグの前に数十の <script>
タグが含まれている場合、画像リソースの読み込みが開始されるまでに時間がかかることがあります。
この問題を解決する最も簡単な方法は、LCP 画像を読み込む <img>
タグまたは <link>
タグに新しい fetchpriority="high"
属性を設定して、どのリソースが最優先されているかをブラウザに知らせることです。これにより、ブラウザはスクリプトの完了を待たずに、そのスクリプトをより早く読み込むように指示できます。
ウェブ アルマナックによると、適格なページの 0.03% のみがこの新しい API を利用しています。つまり、ウェブ上のほとんどのサイトは、ほとんど労力をかけずに LCP を改善できる余地が十分にあります。現在、fetchpriority
属性は Chromium ベースのブラウザでのみサポートされていますが、他のブラウザでは無視される段階的な拡張機能であるため、デベロッパーに今すぐ使用することを強くおすすめします。
Chromium 以外のブラウザの場合、LCP リソースが他のリソースより優先されるようにする唯一の方法は、ドキュメントの前半で LCP リソースを参照することです。ここでも、ドキュメントの <head>
に <script>
タグが多数あるサイトの例で説明しますが、スクリプト リソースよりも LCP リソースを優先させたい場合は、いずれかのスクリプトの前に <link rel="preload">
タグを追加するか、<body>
の後半で、これらのスクリプトを <img>
の下に移動します。これは機能しますが、fetchpriority
を使用する場合よりも人間工学的に劣るため、他のブラウザでも近日中にサポートされる予定です。
LCP リソースの優先順位付けのもう 1 つの重要な点は、loading="lazy"
属性の追加など、LCP リソースの優先順位を下げるようなことは行わないようにすることです。現在、10% のページで実際に LCP 画像に loading="lazy"
が設定されています。遅延読み込み動作を無差別にすべての画像に適用する画像最適化ソリューションに注意してください。この動作をオーバーライドする方法が提供されている場合は、LCP 画像に必ずその動作を使用してください。どの画像が LCP になるか不明な場合は、ヒューリスティックを使用して妥当な候補を選択してみてください。
重要性の低いリソースを遅延させることも、LCP リソースの相対的な優先度を効果的に高める方法です。たとえば、ユーザー インターフェースを活用していないスクリプト(分析スクリプトやソーシャル ウィジェットなど)は、load
イベントが発生するまで安全に延期できます。これにより、ネットワーク帯域幅をめぐって他の重要なリソース(LCP リソースなど)と競合することはありません。
まとめると、LCP リソースが早期かつ高い優先度で読み込まれるように、以下のベスト プラクティスに従うべきです。
- LCP イメージの
<img>
タグにfetchpriority="high"
を追加します。LCP リソースが<link rel="preload">
タグを介して読み込まれる場合は、それにfetchpriority="high"
を設定することもできますので、心配はいりません。 - LCP イメージの
<img>
タグにloading="lazy"
を設定しないでください。これを行うと、画像の優先度が下がり、読み込みの開始が遅くなります。 - 可能であれば、重要でないリソースを先送りする。その場合は、画像をドキュメントの末尾に移動するか、画像や iframe にネイティブ遅延読み込みを使用するか、JavaScript を使用して非同期で読み込みます。
CDN を使用してドキュメントとリソースの TTFB を最適化する
前の 2 つの推奨事項では、LCP リソースを早期に発見し、すぐに読み込みを開始できるように優先順位を付けることに重点を置いていました。このパズルの最後のピースは、ドキュメントの最初の回答をできるだけ早く届けられるようにすることです。
ブラウザは、最初の HTML ドキュメント レスポンスの最初のバイトを受け取るまで、サブリソースの読み込みを開始できません。このタイミングが早ければ、他のあらゆる処理も早く開始されます。
この時間は最初のバイトまでの時間(TTFB)と呼ばれ、TTFB を短縮する最善の方法は以下のとおりです。
- 可能な限りユーザーに地理的に近い場所でコンテンツを配信する
- そのコンテンツをキャッシュに保存して、最近リクエストしたコンテンツをすばやく再提供できるようにする。
この 2 つのことを行うための最善の方法は、CDN を使用することです。CDN は、世界中に分散するエッジ サーバーにリソースを分散します。これにより、リソースが有線でユーザーに到達するまでの距離が制限されます。また、CDN には通常、サイトのニーズに合わせてカスタマイズして最適化できるきめ細かいキャッシュ制御が備わっています。
多くのデベロッパーは、CDN を使用して静的アセットをホストすることに慣れていますが、CDN は、動的に生成されたものも含め、HTML ドキュメントを提供してキャッシュに保存することもできます。
Web Almanac によると、HTML ドキュメント リクエストの 29% のみが CDN から配信されており、サイトにとってはさらなる節約を主張できる大きなチャンスがあります。
CDN を設定する際のヒントは次のとおりです。
- コンテンツをキャッシュに保存する期間を長くすることを検討する(たとえば、コンテンツが常に最新であることが実際に重要かどうか、数分間古くなったりなど)。
- コンテンツを無期限にキャッシュして、更新を行ったときにキャッシュを削除することを検討してください。
- 配信元サーバーで現在実行中の動的ロジックをエッジ(最新の CDN の機能であるほとんど)に移動できるかどうかを確認する。
一般的に、(配信元サーバーへの移動を回避して)エッジから直接コンテンツを配信できれば、パフォーマンスが向上します。配信元サーバーまで遡る必要がある場合であっても、通常 CDN はこの処理を高速化するように最適化されているため、どちらの場合でもメリットがあります。
Cumulative Layout Shift(CLS)
次の推奨事項は、ウェブページの視覚的な安定性の指標である Cumulative Layout Shift(CLS)です。2020 年以降、ウェブ上での CLS は大きく改善されましたが、ウェブサイトの約 4 分の 1 がまだ推奨しきい値を満たしていないため、多くのサイトにとって、ユーザー エクスペリエンスを向上させる大きなチャンスが残されています。
ページから読み込まれるコンテンツに明示的なサイズを設定する
レイアウト シフトは通常、既存のコンテンツが他のコンテンツの読み込みを完了した後に移動する場合に発生します。そのため、この問題を軽減する主な方法は、必要なスペースを可能な限り事前に確保しておくことです。
サイズ調整されていない画像によるレイアウト シフトを修正する最も簡単な方法は、width
属性と height
属性(または同等の CSS プロパティ)を明示的に設定することです。しかし、HTTP アーカイブによると、72% のページにサイズ未指定の画像が少なくとも 1 つ含まれています。サイズを明示的に指定しない場合、ブラウザは最初にデフォルトの高さ 0px
を設定します。そのため、画像が最終的に読み込まれてサイズが検出されたときに、レイアウトが著しくシフトする可能性があります。これは、ウェブ全体にとって大きな機会であり、また、この記事で提案されている他の推奨事項よりもはるかに少ない労力でチャンスが得られることを意味します。
また、CLS に貢献しているのはイメージだけではないことに注意する必要があります。第三者の広告や埋め込み動画など、通常はページが最初にレンダリングされた後に読み込まれる他のコンテンツによって、レイアウト シフトが発生することがあります。aspect-ratio
プロパティは、これに対処するのに役立ちます。これは比較的新しい CSS 機能で、デベロッパーは画像要素と非画像要素の両方でアスペクト比を明示的に指定できます。これにより、(画面サイズなどに基づいて)動的な width
を設定し、寸法を含む画像の場合とほぼ同じ方法で、ブラウザが適切な高さを自動的に計算できるようになります。
動的コンテンツは、その性質上、動的であるため、正確なサイズを把握できない場合があります。ただし、正確なサイズがわからない場合でも、レイアウト シフトの重大度を下げる手段を講じることができます。ほとんどの場合、ブラウザで空の要素にデフォルトの高さ 0px
の使用を許可するよりも、適切な min-height
を設定することをおすすめします。min-height
を使用することも、通常は簡単に修正できます。コンテナは、必要に応じて最終的なコンテンツの高さまで拡張できます。増加量を全体から許容可能なレベルまで減らしただけです。
ページが bfcache の対象であることを確認する
ブラウザは、バックフォワード キャッシュ(略して bfcache)と呼ばれるナビゲーション メカニズムを使用して、ブラウザ履歴の以前または後のページをメモリのスナップショットから直接、瞬時に読み込みます。
bfcache は、ブラウザレベルのパフォーマンスを大幅に最適化し、多くのサイトでは CLS のほとんどが発生するページ読み込み時のレイアウト シフトを完全に排除します。bfcache の導入は、2022 年に確認された CLS の最大の改善を引き起こしました。
それにもかかわらず、かなりの数のウェブサイトが bfcache の対象外であり、多くのナビゲーションにおいてこの無料のウェブ パフォーマンスのメリットを逃しています。メモリから復元したくない機密情報をページに読み込んでいる場合を除き、ページがこの機能の対象となることを確認する必要があります。
サイト所有者は、自身のページが bfcache の対象であることを確認し、適用されない原因に対処する必要があります。Chrome にはすでに DevTools に bfcache テスターがありますが、今年はツールを強化し、同様のテストを行う新しい Lighthouse の監査と、実際にこれを測定する API を用意する予定です。
CLS セクションに bfcache を追加しましたが、これまでに最大のメリットが見られたように、bfcache は一般的に他の Core Web Vitals も改善します。ページ ナビゲーションを大幅に改善するために利用できる多くのインスタント ナビゲーションの一つです。
レイアウトを引き起こす CSS プロパティを使用するアニメーションや遷移を避ける
レイアウト シフトが発生するもう一つの一般的な原因は、要素がアニメーション化されたときです。たとえば、上部または下部からスライドして表示される Cookie バナーやその他の通知バナーは、多くの場合 CLS の要因となっています。特に問題となるのは、このようなバナーによって他のコンテンツが邪魔にならないように見えても、アニメーション化しても CLS に影響を与える可能性があります。
HTTP Archive のデータでは、アニメーションとレイアウト シフトを結論付けることはできませんが、レイアウトに影響を与える可能性がある CSS プロパティをアニメーション化するページは、ページ全体よりも CLS が「良好」になる可能性が 15% 低いことを示しています。一部のプロパティは、他のプロパティよりも CLS が低くなります。たとえば、margin
幅または border
幅をアニメーション化するページの CLS は、ページ全体で低と評価される約 2 倍の割合です。
レイアウトを誘導する CSS プロパティをなんらかの移動またはアニメーション化するたびにレイアウト シフトが発生し、そのレイアウト シフトが CLS から 500 ミリ秒以内に影響しないため、これは驚くことではありません。
一部のデベロッパーにとって驚くかもしれませんが、要素が通常のドキュメント フローの外で取得された場合でも、このことが当てはまります。たとえば、top
または left
をアニメーション化する絶対的な位置にある要素は、他のコンテンツを押し付けていない場合でもレイアウト シフトが発生します。ただし、top
または left
ではなく、transform:translateX()
または transform:translateY()
をアニメーション化した場合、ブラウザはページ レイアウトを更新しないため、レイアウト シフトは発生しません。
ブラウザのコンポジタ スレッドで更新できる CSS プロパティのアニメーションは、GPU とメインスレッドからの処理を移動させるため、長い間、パフォーマンス上のベスト プラクティスでした。この方法は、パフォーマンスに関する一般的なベスト プラクティスであることに加え、CLS の向上にも役立ちます。
原則として、ブラウザによるページ レイアウトの更新を必要とする CSS プロパティをアニメーション化したり移行したりしないでください。ただし、ユーザーのタップやキー操作に応じて行う場合を除きます(ただし、hover
ではありません)。また、可能な限り、CSS の transform
プロパティを使用して移行とアニメーション化を行ってください。
Lighthouse の監査では、ページのアニメーションで CSS プロパティの速度が低下する可能性がある場合に、非合成アニメーションを避けるという警告が表示されます。
First Input Delay(FID)
最後の推奨事項は、ユーザー操作に対するページの応答性を示す指標である初回入力遅延(FID)です。現在、ウェブ上のほとんどのサイトで FID のスコアが良好になっていますが、Google は過去に FID 指標の欠点を文書化してきました。Google では、ユーザー操作に対する全体的な応答性を改善できる余地はまだたくさんあると Google は考えています。
Google の新しい Interaction to Next Paint(INP)指標は FID の後継となる可能性があり、以下のすべての推奨事項は FID と INP の両方に同じように適用されます。特にモバイルでは、INP に関してサイトの INP の方がパフォーマンスが悪いことを考えると、「良い」FID であっても、デベロッパーはこれらの応答性に関する推奨事項を真剣に検討することをおすすめします。
長いタスクを避ける、分割する
タスクとは、ブラウザが実行する個別の作業のことです。タスクには、スクリプトのレンダリング、レイアウト、解析、コンパイル、実行が含まれます。タスクが長いタスク(50 ミリ秒以上)になると、メインスレッドがユーザー入力に迅速に応答できなくなります。
ウェブ アルマナックによると、デベロッパーが長いタスクを回避または分割するために、さらなる対策を講じることができることを示唆する証拠はたくさんあります。時間のかかるタスクを分割することは、この記事で紹介している他の推奨事項ほど手間がかからないかもしれませんが、この記事で紹介していない他の手法よりも簡単です。
JavaScript で行う作業はできる限り少なくする必要がありますが、長いタスクを小さなタスクに分割することで、メインスレッドを大幅に効率化することができます。これを行うには、頻繁にメインスレッドに譲ることで、レンダリングの更新やその他のユーザー操作をより迅速に行えるようにします。
もう一つの選択肢は、isInputPending
などの API や Scheduler API を使用することです。isInputPending
は、ユーザー入力が保留中かどうかを示すブール値を返す関数です。true
が返された場合は、保留中のユーザー入力を処理できるようにメインスレッドに譲ることができます。
Scheduler API はより高度なアプローチであり、実行中の作業がユーザーに表示されるかバックグラウンドで行われるかを考慮した優先度システムに基づいて作業のスケジュールを設定できます。
長いタスクを分割することで、インタラクションの処理やその結果生じるレンダリングの更新など、ユーザーが認識できる重要な作業にブラウザが適合する機会が増えます。
不要な JavaScript を避ける
ウェブサイトでの JavaScript の処理量はかつてないほど増えており、この傾向はすぐには変わらないようです。JavaScript を使いすぎると、メインスレッドの注意を奪うためにタスクが競合する環境ができてしまいます。これは、特に重要なスタートアップ期間中は、ウェブサイトの応答性に間違いなく影響する可能性があります。
しかし、これは解決できない問題ではありません。次のような方法があります。
- Chrome DevTools のカバレッジ ツールを使用して、ウェブサイトのリソースで使用されていないコードを見つけます。起動時に必要なリソースのサイズを削減することで、ウェブサイトでコードの解析やコンパイルに費やす時間を減らし、最初のユーザー エクスペリエンスをよりスムーズにすることができます。
- カバレッジ ツールを使用して見つけた未使用のコードは、起動時には実行されなかったものの、将来のいくつかの機能に必要なため「未使用」とマークされることがあります。このコードは、コード分割によって別のバンドルに移動できます。
- タグ マネージャーを使用している場合は、(まだ使用している場合でも)タグが最適化されているかどうかを定期的に確認してください。使用されていないコードを含む古いタグを削除すると、タグ マネージャーの JavaScript のサイズを小さくして効率的になります。
大規模なレンダリングの更新を避ける
ウェブサイトの応答性に影響を与える可能性があるのは JavaScript だけではありません。レンダリングはそれ自体はコストの高い作業です。大規模なレンダリングの更新が発生すると、ウェブサイトのユーザー入力に応答する機能が妨げられる可能性があります。
レンダリング処理の最適化は単純なプロセスではなく、多くの場合、何を達成しようとしているかによって異なります。それでも、レンダリングの更新が妥当であることを確認し、長いタスクに無秩序に乱入しないようにするために、できることがいくつかあります。
requestAnimationFrame()
を視覚的でない処理に使用することは避けてください。requestAnimationFrame()
呼び出しは、イベントループのレンダリング フェーズで処理されます。このステップで行われる作業が多すぎると、レンダリングの更新が遅れることがあります。requestAnimationFrame()
を使用して行う作業は、レンダリングの更新を含むタスク専用に予約することが重要です。- DOM サイズを小さくします。DOM サイズとレイアウト作業の負荷には相関関係があります。非常に大きな DOM のレンダラがレイアウトを更新する必要がある場合、レイアウトを再計算するために必要な作業が大幅に増える可能性があります。
- CSS コンテインメントを使用します。CSS の包含は、CSS
contain
プロパティに依存します。このプロパティは、contain
プロパティが設定されているコンテナのレイアウト作業(レイアウトの範囲の分離や DOM 内の特定のルートへのレンダリングなど)を行う方法をブラウザに指示します。これは必ずしも簡単なプロセスではありませんが、複雑なレイアウトを含む領域を分離することで、不要なレイアウトとレンダリング作業を回避できます。
まとめ
ページ パフォーマンスの改善は、特にウェブ全体で考慮すべきガイダンスが山ほどあることを考えると、大変な作業に思えるかもしれません。しかし、これらの推奨事項に重点を置くことで、焦点と目的を持って問題に取り組み、ウェブサイトの Core Web Vitals に変化をもたらすことができます。
ここに記載されている推奨事項はすべてを網羅しているわけではありませんが、ウェブの状態の慎重な分析に基づいて、2023 年にサイトが Core Web Vitals のパフォーマンスを向上させるには、これらの推奨事項が最も効果的であると Google は考えています。
ここに示す推奨事項以外のヒントをご希望の場合は、以下の最適化ガイドをご覧ください。
新年に向けて、より高速なウェブをすべての人に迎えましょう。サイトの利便性を最も重視する形でユーザーに届けましょう。
写真撮影: Devin Avery