loading-sequence について
Web 開発者向けに、CSS、フォント、画像、ファーストパーティおよびサードパーティの JavaScript の読み込み順を調整し、Core Web Vitals に対応する方法を解説するガイドです。
主な機能
- 01FCP、LCP、操作性に沿ったリソース順序
- 02重要な CSS のインライン化とフォント接続の先行
- 03重要でないスクリプトと画面外画像の遅延
- 04サードパーティスクリプトとブラウザー優先度の考慮
活用シーン
- 01サードパーティスクリプトによる読み込み遅延の調査
- 02重要な CSS、フォント、初期表示画像の順序調整
- 03ページの Core Web Vitals の改善
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ patternsdev/ skills --skill loading-sequenceインストール後、Claude Code で/loading-sequenceを入力して読み込まれたか確認します。
詳細
読み込み順序を最適化する
目次
Web ページの読み込みが正常に完了すると、重要なコンポーネントやリソースが適切なタイミングで利用可能になり、スムーズな読み込み体験が実現します。これにより、ユーザーはアプリケーションのパフォーマンスが優れていると感じます。この優れたユーザー体験は、一般に Core Web Vitals の合格にもつながります。
使用するタイミング
- Core Web Vitals のためにページ読み込みのパフォーマンスを最適化する場合に使用します
- 1P JS、3P JS、CSS、フォント、画像の読み込みを調整する必要がある場合に役立ちます
- サードパーティのスクリプトが読み込みパフォーマンスに影響している場合に使用します
手順
- 重要な CSS とフォントの CSS をインライン化し、外部フォントには preconnect を使用します
- FCP が LCP より先に発生し、LCP が FID より先に発生するようにリソースの順序を調整します
- ネットワーク上で、ATF 画像より先にファーストパーティの JS の取得を開始します
- 重要でないスクリプトには
asyncまたはdefer属性を使用します - 画面下部の画像と、必須ではないサードパーティのリソースは遅延読み込みします
詳細
パフォーマンスの測定に使用される First Content Paint、Largest Contentful Paint、First Input Delay などの主要な指標は、重要なリソースの読み込み順序に直接左右されます。たとえば、ヒーロー画像のような重要なリソースが読み込まれていなければ、ページで LCP は発生しません。この記事では、リソースの読み込み順序と Web Vitals の関係について説明します。Web Vitals を向上させるため、読み込み順序を最適化する方法を明確に示すことが目的です。
理想的な読み込み順序を決める前に、まず、読み込み順序を適切に設定するのがなぜ難しいのかを理解しましょう。
最適な読み込み順序の実現が難しいのはなぜですか?
私たちは、複数のパートナーのウェブサイトでパフォーマンス分析に取り組む貴重な機会を得てきました。その中で、パートナーごとに異なるサイトにおいて、ページの効率的な読み込みを妨げる、共通した問題をいくつも特定しました。
開発者の期待と、ブラウザーがページ上のリソースに優先順位を付ける方法との間には、しばしば大きな隔たりがあります。その結果、パフォーマンススコアが最適でなくなることがよくあります。さらに分析を進め、この隔たりの原因を調査したところ、分析の要点は次のとおりでした。
最適でない読み込み順序
Web Vitals の最適化には、各指標が何を表すかを理解するだけでなく、指標の発生順序や、それぞれが異なる重要なリソースとどのように関係するかを把握する必要があります。FCP は LCP より先に発生し、LCP は FID より先に発生します。そのため、FCP の達成に必要なリソースを、LCP に必要なリソースより優先し、さらにその後に FID に必要なリソースを配置する必要があります。
リソースの順序付けとパイプライン化が適切に行われていないことがよくあります。これは、指標がリソースの読み込みに依存していることを開発者が把握していないためかもしれません。その結果、対応する指標が発生する適切なタイミングで、関連するリソースが利用できないことがあります。
例:
a) FCP が発生する時点で、LCP を発生させるためのヒーロー画像が利用可能になっている必要があります。 b) LCP が発生する時点で、操作を可能にするため、JavaScript(JS)のダウンロードと解析が完了し、実行可能な状態(またはすでに実行中)になっている必要があります(FID)。
ネットワーク/CPU の使用率
CPU とネットワークを十分に活用できるよう、リソースが適切にパイプライン化されていないこともあります。その結果、プロセスがネットワーク待ちのときに CPU に「デッドタイム」が生じ、その逆も発生します。 同時または順次ダウンロードされるスクリプトは、その好例です。同時ダウンロード中は帯域幅が分割されるため、すべてのスクリプトをダウンロードするのにかかる合計時間は、順次ダウンロードでも同時ダウンロードでも同じです。スクリプトを同時にダウンロードすると、ダウンロード中に CPU が十分に活用されません。一方、スクリプトを順次ダウンロードすると、最初のスクリプトがダウンロードされた時点で、CPU はその処理を開始できます。その結果、CPU とネットワークをより効率的に活用できます。
サードパーティ(3P)製品
ウェブサイトに一般的な機能を追加するには、3P ライブラリが必要になることがよくあります。サードパーティには、広告、分析、ソーシャルウィジェット、ライブチャットなど、ウェブサイトを支えるさまざまな埋め込みコンテンツが含まれます。サードパーティのライブラリには、独自の JavaScript、画像、フォントなどが含まれています。
3P 製品は通常、導入先サイトの読み込みパフォーマンスを最適化し、サポートする動機がありません。インタラクティブになるまでの時間を遅らせるほど JavaScript の実行コストが高かったり、ほかの重要なリソースのダウンロードを妨げたりすることがあります。
3P 製品を導入する開発者は、パフォーマンスへの影響よりも、機能面での付加価値に目を向けがちです。その結果、読み込み全体の順序にどう組み込むかを十分に検討せず、3P リソースが場当たり的に追加されることがあります。そのため、制御やスケジュール設定が難しくなります。
プラットフォーム固有の挙動
リクエストの優先順位付けやヒントの実装方法は、ブラウザーによって異なる場合があります。プラットフォームとその固有の挙動を深く理解していれば、最適化は容易になります。特定のブラウザーに固有の挙動があると、望ましい読み込み順序を一貫して実現するのが難しくなります。
その一例が、Chromium プラットフォームの preload のバグです。Preload(<link rel=preload>)命令を使うと、重要なリソースをできるだけ早くダウンロードするようブラウザーに指示できます。この命令は、そのリソースが現在のページで使われると確信できる場合にのみ使用してください。Chromium のこのバグにより、<link rel=preload> 経由で発行されたリクエストは、プリロードスキャナーが検出したほかのリクエストの優先度が高くても、常にそれらより先に開始されます。このような問題は、最適化計画を妨げます。
HTTP2 の優先順位付け
プロトコル自体には、リソースの順序や優先度を調整するためのオプションや設定項目があまりありません。より優れた優先順位付けのプリミティブが利用できるようになったとしても、最適な順序付けを難しくする、HTTP2 の優先順位付けに関する根本的な問題があります。主な問題は、サーバーや CDN が個々のリソースのリクエストにどのような順序で優先順位を付けるか予測できないことです。優先順位を再設定する CDN もあれば、一部だけ、誤った方法、あるいはまったく優先順位を付けない CDN もあります。
リソースレベルの最適化
効果的な順序付けには、対象のリソースが速やかに読み込まれるよう、最適な形で配信される必要があります。重要な CSS はインライン化し、画像は適切なサイズにし、JS はコード分割して段階的に配信する必要があります。
フレームワーク自体には、コード分割を可能にし、JS とデータを段階的に配信するための構成要素が不足しています。ユーザーは、大きな 1P JS のコード分割に、次のいずれかを利用する必要があります。
- モダンな React(Suspense/Concurrent mode/データ取得)— 現時点では、実験目的でのみ利用できます
- 動的インポートによる遅延読み込み — 直感的な方法ではなく、開発者がコードを分割する境界を手動で特定する必要があります。
コードを分割する際は、細分化の度合いとパフォーマンスとのトレードオフがあるため、開発者はチャンクの粒度を適切に調整する必要があります。
粒度を高くすることが望ましい理由は、次のとおりです。
- 個々のルートや、その後のユーザー操作に必要な JS を最小限に抑えます
- 共通の依存関係をキャッシュできます。これにより、ライブラリに変更があっても、バンドル全体を再取得する必要がなくなります。
一方、コード分割を細かくしすぎると問題になることがあります。小さなチャンクが多すぎると、チャンクごとの圧縮率が低下し、ブラウザーのパフォーマンスにも影響します。
リソースを最適化するには、不要なコードや未使用のコードを削除することも必要です。不要または古い JS が最新のブラウザーに配信されることがよくあり、パフォーマンスに悪影響を及ぼします。ES5 にトランスパイルされ、ポリフィルとともにバンドルされた JS は、最新のブラウザーには不要です。ライブラリや npm パッケージは、ES モジュール形式で公開されていないことがよくあります。そのため、バンドラーによるツリーシェイキングと最適化が難しくなります。
お気づきかもしれませんが、こうした問題は特定のリソースやプラットフォームに限られません。これらの問題に対処するには、技術スタック全体と、最適な指標を実現するために異なるリソースをどのように組み合わせるかを理解する必要があります。
リソースについてさらに詳しく — 関係、制約、優先順位
前のセクションでは、FCP や LCP などのイベントが発生するために必要となるリソースの例をいくつか紹介しました。これらの依存関係をすべて理解してから、それらを扱う方法について説明します。理想的な順序を定義する前に考慮する必要がある推奨事項、制約、注意点を、リソースごとに以下に示します。
クリティカル CSS
クリティカル CSS とは、FCP に必要な最小限の CSS を指します。このような CSS は、別の CSS ファイルからインポートするよりも HTML 内にインライン化するほうが適切です。その時点で必要なルートの CSS のみをダウンロードし、クリティカル CSS はすべて適切に分割する必要があります。
インライン化できない場合、クリティカル CSS はプリロードし、ドキュメントと同じオリジンから配信する必要があります。クリティカル CSS を複数のドメインから配信したり、Google Fonts などのサードパーティのクリティカル CSS を直接使用したりするのは避けてください。代わりに、自社のサーバーをサードパーティのクリティカル CSS のプロキシとして使用できます。
CSS の取得が遅れたり、取得順序が不適切だったりすると、FCP や LCP に影響する可能性があります。これを避けるには、インライン化されていない CSS の優先度を上げ、ネットワーク上で 1P JS や ATF 画像より先に配置する必要があります。
インライン化する CSS が多すぎると、HTML が肥大化し、メインスレッドでのスタイル解析に時間がかかります。これにより FCP が悪化する可能性があります。そのため、クリティカルな内容を特定し、コード分割することが不可欠です。
インライン化された CSS はキャッシュできません。この問題への対処法の一つは、キャッシュ可能な CSS に対して重複したリクエストを行うことです。ただし、その結果、ページ全体のレイアウトが複数回発生し、FID に影響する可能性がある点に注意してください。
フォント
クリティカル CSS と同様に、クリティカルフォントの CSS もインライン化する必要があります。インライン化できない場合は、preconnect を指定してスクリプトを読み込む必要があります。フォントの取得が遅れると、たとえば Google Fonts や別のドメインから取得するフォントの場合、FCP に影響する可能性があります。preconnect を指定すると、ブラウザーはこれらのリソースへの接続を早期に確立します。
フォントをインライン化すると HTML が大幅に肥大化し、ほかの重要なリソースの取得開始が遅れる可能性があります。フォントフォールバックを使用すると、FCP を妨げずにテキストを表示できます。ただし、フォントが切り替わることで、フォントフォールバックは CLS に影響する可能性があります。また、実際のフォントが読み込まれたときにメインスレッドで大きなスタイルおよびレイアウト処理が発生する可能性があるため、FID にも影響することがあります。
ファーストビュー(ATF)画像
これは、ページ読み込み時にビューポート内にあるため、ユーザーに最初に表示される画像を指します。ATF 画像の特別な例として、ページのヒーロー画像があります。すべての ATF 画像にはサイズを指定する必要があります。サイズが指定されていない画像は、完全にレンダリングされたときにレイアウトシフトが発生するため、CLS 指標を悪化させます。ATF 画像のプレースホルダーはサーバー側でレンダリングする必要があります。 ヒーロー画像の読み込みが遅れたり、プレースホルダーが空白だったりすると、LCPが遅くなります。さらに、プレースホルダーのサイズが実際のヒーロー画像の本来のサイズと一致せず、置き換え時に画像が重ねて表示されない場合、LCPが再度発生します。理想的には、ATF画像によるFCPへの影響はないはずですが、実際には画像がFCPを発生させることがあります。
スクロールせずに見えない位置(BTF)の画像
これらは、ページの読み込み時にユーザーからすぐには見えない画像です。そのため、遅延読み込みに最適な対象です。これにより、ページ上で必要な1P JSや重要な3Pリソースとの競合を防げます。BTF画像が1P JSや重要な3Pリソースより先に読み込まれると、FIDが遅延します。
1P JavaScript
1P JSはアプリケーションのインタラクション可能になるまでの時間に影響します。ネットワーク上では画像や3P JSより後になり、メインスレッドでは3P JSより後になることで、読み込みが遅れる可能性があります。そのため、ネットワーク上ではATF画像より先に読み込みを開始し、メインスレッドでは3P JSより先に実行する必要があります。サーバーサイドでレンダリングされるページでは、1P JSはFCPやLCPをブロックしません。
3P JavaScript
HTMLのhead内にある3P同期スクリプトはCSSやフォントの解析をブロックし、FCPを遅らせる可能性があります。また、head内の同期スクリプトはHTMLのbodyの解析もブロックします。メインスレッドでの3Pスクリプトの実行は、1Pスクリプトの実行を遅らせ、ハイドレーションやFIDを遅延させる可能性があります。そのため、3Pスクリプトの読み込みをより適切に制御する必要があります。
これらの推奨事項と制約は、一般に技術スタックやブラウザーに関係なく当てはまります。推奨事項が制約にもなり得る点に注意してください。たとえば、フォントやCSSのインライン化は有効ですが、量が多すぎると肥大化を招きます。「少なすぎて遅すぎる」状態と「多すぎて早すぎる」状態のバランスを見つけることが重要です。
Chromeのリソース優先度テーブルから得られる主なポイントは次のとおりです。
- CSSとフォントは最も高い優先度で読み込まれます。これにより、重要なCSSとフォントの優先度を高くできます。
- スクリプトの優先度は、ドキュメント内の位置と、async、defer、またはブロッキングのどれに該当するかに応じて異なります。最初の画像(またはドキュメント内の早い位置にある画像)より前にリクエストされたブロッキングスクリプトは、最初の画像が取得された後にリクエストされたブロッキングスクリプトよりも高い優先度になります。ドキュメント内の位置にかかわらず、async、defer、または挿入されたスクリプトの優先度は最も低くなります。そのため、asyncとdeferに適切な属性を指定することで、スクリプトごとの優先度を設定できます。
- 表示領域内にあり、ビューポート内に表示される画像は、ビューポート外の画像よりも高い優先度(ネットワーク:中)になります(ネットワーク:最低)。これにより、BTF画像よりもATF画像を優先できます。
それでは、以上の内容を組み合わせて、最適な読み込み順序を定義する方法を見ていきましょう。
理想的な読み込み順序とは
以上を踏まえて、1Pと3P両方のリソースの読み込みを最適化する読み込み順序を提案できます。提案する順序では、最適化の参考としてNext.jsのサーバーサイドレンダリング(SSR)を使用します。
現状
これまでの経験から、最適化前のNext.js SSRアプリケーションでは、一般的に次のような読み込み順序が見られました。
| リソース | 状態 |
|---|---|
| CSS | CSSはJSより先にプリロードされますが、インライン化されていません |
| JavaScript | 1P JSはプリロードされます。3P JSは管理されておらず、ドキュメント内のどこにあってもレンダリングをブロックする可能性があります。 |
| フォント | フォントはインライン化されておらず、preconnectも使用していません。フォントは外部スタイルシート経由で読み込まれるため、読み込みが遅れます。フォントが描画をブロックする場合と、しない場合があります。 |
| 画像 | ヒーロー画像は優先されていません。ATF画像もBTF画像も最適化されていません。 |
3P を含まない場合に推奨される順序
以下は、これまでに説明したすべての制約を考慮した読み込み順序です。まずは 3P を含まない順序を見ていきましょう。その後、この順序に 3P リソースをどのように組み込めるかを確認します。ここでは Google Fonts を 1P として扱っていることにご注意ください。
| #(メインスレッド) | イベント | #(ネットワーク) | リクエスト |
|---|---|---|---|
| 1 | HTML を解析 | 1 | 小さなインライン 1P スクリプト |
| 2 | 小さなインライン 1P スクリプトを実行 | 2 | インライン化されたクリティカル CSS(外部の場合はプリロード) |
| 3 | インライン化されたクリティカルフォント(外部の場合はプリコネクト) | ||
| 3 | FCP リソース(クリティカル CSS、フォント)を解析 | 4 | LCP 画像(外部の場合はプリコネクト) |
| FCP | 5 | フォント(インラインのフォント CSS から開始、プリコネクト) | |
| 4 | LCP リソース(ヒーロー画像、テキスト)をレンダリング | 6 | クリティカルではない CSS(非同期) |
| 7 | インタラクティブ機能のためのファーストパーティ JS | ||
| 8 | ファーストビューの画像(プリコネクト) | ||
| LCP | 9 | ファーストビュー以降の画像 | |
| 5 | 重要なファーストビュー画像をレンダリング | ||
| 視覚的な読み込み完了 | |||
| 6 | クリティカルではない CSS(非同期)を解析 | ||
| 7 | 1P JS を実行してハイドレーション | 10 | 遅延読み込みされる JS チャンク |
| FID |
この順序の一部は直感的に思えるかもしれませんが、以下の点を踏まえると、さらに納得できるはずです。
- プリロードは、先行するすべてのリソースに対して手動でプリロードを指定する必要があり、順序も手動で調整する必要があるため、できる限り避けることをおすすめします。特にフォントへのプリロードは、クリティカルなフォントの特定が難しいため、避けるべきです。
- フォント CSS は、できればインライン化してください。別のオリジンからのフォントは、プリコネクトを使用して取得してください。
- 別のオリジンからのすべてのリソースに対して、プリコネクトをおすすめします。これにより、これらのリソースをダウンロードするための接続を事前に確立できます。
- クリティカルではない CSS は、ユーザーのインタラクションが始まる前(FID)に取得してください。これにより、そのような CSS の後続のレンダリングによるスタイルの問題を防げます。
- ネットワーク上では、ファーストビュー画像より先にファーストパーティ JS の取得を開始してください。JS のダウンロードと解析には時間がかかります。
- メインスレッドでの HTML の解析とファーストビュー画像のダウンロードは、1P JS の解析中も並行して続けることができます。
3P を含む場合の推奨シーケンス
最後に、最新の Web アプリケーションで一般的に読み込まれるすべての主要なリソースについて、シーケンスを提案します。3P リソースを含めた場合、メインブラウザースレッド上のイベントとネットワークリクエストのシーケンスは次のようになります。
| # | メインスレッドのイベント | ネットワークリクエスト |
|---|---|---|
| 1 | HTML を解析 | FCP をブロックする 3P リソース |
| 2 | ||
| 3 | 小さなインライン 1P スクリプト | |
| 4 | 小さなインライン 1P スクリプトを実行 | インライン化されたクリティカル CSS(外部の場合はプリロード) |
| 5 | FCP をブロックする 3P リソースを解析 | インライン化されたクリティカルフォント(外部の場合は事前接続) |
| 6 | FCP リソース(クリティカル CSS、フォント)を解析 | LCP に必要な、3P によってパーソナライズされた ATF 画像 |
| 7 | FCP | LCP 画像(外部の場合は事前接続) |
| 8 | LCP に必要な、3P によってパーソナライズされた ATF 画像を描画 | フォント(インラインフォント CSS から読み込み、事前接続) |
| 9 | クリティカルでない(非同期)CSS | |
| 10 | LCP リソース(ヒーロー画像、テキスト)を描画 | 最初のユーザー操作より前に実行する必要がある 3P |
| 11 | インタラクティブ機能用の 1P JavaScript | |
| 12 | LCP | |
| 13 | 重要な ATF 画像を描画 | デフォルトの 3P JavaScript |
| 14 | クリティカルでない(非同期)CSS を解析 | |
| 15 | 最初のユーザー操作に必要な 3P を実行 | フォールドより下の画像 |
| 16 | 1P JavaScript を実行してハイドレーション | 遅延読み込みされる JavaScript チャンク |
| FID | 重要度の低い 3P JavaScript |
ここで主に考慮すべきなのは、3P スクリプトを最適な形で、必要なシーケンスどおりにダウンロードするにはどうすればよいかという点です。
スクリプトのリクエストは別のドメインに送信されるため、次の 3P リクエストでは事前接続を推奨します。
- #1 - FCP をブロックする 3P リソース
- #5 - LCP に必要な、3P によってパーソナライズされた ATF 画像
- #9 - 最初のユーザー操作より前に実行する必要がある 3P
- #12 - デフォルトの 3P JavaScript
目的のシーケンスを実現するには、Next の ScriptLoader コンポーネントを使用することをお勧めします。このコンポーネントは、「クリティカルレンダリングパスを最適化し、外部スクリプトが最適なページ読み込みのボトルネックにならないようにする」ために設計されています。今回の説明に最も関連する機能は、読み込み優先度です。これにより、さまざまなユースケースに対応するため、異なるマイルストーンでスクリプトをスケジュールできます。利用可能な読み込み優先度の値は次のとおりです。
After-Interactive:次のハイドレーション後に、指定した 3P スクリプトを読み込みます。タグマネージャー、広告、分析など、1P スクリプトの後で、できるだけ早く実行したいスクリプトの読み込みに使用できます。
Before-Interactive:ハイドレーション前に、指定した 3P スクリプトを読み込みます。3P スクリプトを 1P スクリプトより先に実行したい場合に使用できます。例:polyfill.io、ボット検出、セキュリティと認証、ユーザー同意管理(GDPR)など。
Lazy-Onload:指定した 3P スクリプトよりも他のすべてのリソースを優先し、スクリプトを遅延読み込みします。Google Feedback などの CRM コンポーネントや、共有ボタン、コメントなどに使われるソーシャルネットワーク固有のスクリプトに使用できます。
このように、事前接続、スクリプト属性、そして Next.js の ScriptLoader を組み合わせることで、すべてのスクリプトを目的のシーケンスで読み込めます。
結論
アプリの最適化は、利用されるプラットフォームの制作者と、それを使用する開発者の双方が担う責任です。よくある問題に対処する必要があります。私たちは、内部から外部へとシーケンスを簡単にできるようにすることを目指しています。さまざまなユースケースに応じた、実証済みの一連の推奨事項や、Script Loader のような取り組みによって、React-Next.js スタックでこれを実現できます。次のステップは、新しいアプリが上記の推奨事項に準拠していることを確認することです。