Lighthouseのネットワーク依存関係ツリー:読み解き方と修正方法
ブラウザが別のファイルの中からしか見つけられないファイルがあると、ページはそれらを順番に待つことになります。ツリーやpreconnectの表をどう読み解くか、そして連鎖をどう短縮するかを解説します。
PageSpeed Insightsの「ネットワーク依存関係ツリー」とは?
Lighthouseのネットワーク依存関係ツリー(Lighthouse 13以前は「Avoid chaining critical requests」)は、ページが最初に必要とするファイルと、各ファイルがどのファイルを待っていたかを示します。ファイルの中から別のファイルを読み込むたびに、待ち時間が増加します。フォントは自ドメインでホストし、スタイルシートは@importではなくHTML内でリンクしてください。そしてpreconnectは、どうしても避けられない外部ドメインから重要なファイルを読み込む場合にのみ使用します。
手短に対処したい場合は、Webフォント、WordPressの@import、Shopify、スクリプトが追加するファイルへ移動してください。
ネットワーク依存関係ツリーはどう読み解くか?
Lighthouse 13とPageSpeed Insightsでは、この項目について次のように説明されています。「ページの読み込みを改善するために、連鎖の長さを短縮し、リソースのダウンロードサイズを減らすか、不要なリソースのダウンロードを遅らせて、重要なリクエストの連鎖を回避してください」。これは「Avoid chaining critical requests」(さらに前は「Minimize critical requests depth」)と「Preconnect to required origins」を統合したものです。ツリーの下にpreconnect関連の表が2つ並んでいるのはそのためです。
以下のレポートは、一般的なWordPressサイトと同じ構成で作成した歯科医院のホームページのものです。子テーマのスタイルシートが親テーマのスタイルシートをインポートし、そこからGoogle Fontsがインポートされ、アイコンはCDN経由でFont Awesomeから読み込まれています。

モバイル版Lighthouse 13.6、DevToolsスロットリング(Slow 4G、CPU 4倍低速化)。
- インデントされた行は、1つ上の階層のファイルの中からしか見つからなかったファイルです。そのため、親ファイルの到着を待つ必要がありました。同じ階層にある行は、Googleのcss2スタイルシートの下にある3つのフォントファイルのように、並行してダウンロードされます。
- 行に表示される時間とKiB:ページの読み込み開始からそのファイルが届くまでの時間と、ファイルサイズを示します。
- Maximum critical path latencyは、最も遅い連鎖にかかった時間で、オレンジ色で表示されます。この歯科医院のページでは、2階層深い位置にある155 KiBのアイコンフォントが該当し、4階層下にあるGoogle Fontsよりも後に届いています。
- LCPとUnscored:この項目自体はPerformanceスコアに影響しません。しかし、対象のスタイルシートはfirst paintを遅らせ、LCPがそれより先に完了することはあり得ません。
PageSpeed Insightsはスロットリングなしで読み込みを記録するため、そのツリーにはこのスクリーンショットよりもはるかに短い時間が表示されます。
ファイルの連鎖はなぜページを遅らせるのか?
この歯科医院のページでは、訪問者の画面にまず白い画面が表示されます。次にfallbackフォントでテキストが表示され、Webフォントが届いた瞬間にフォントが切り替わります。アイコンの位置には空の丸が表示されたままです。
ブラウザはHTMLを先読みし(preload scanner)、そこに見つかったすべてのファイルを一度にリクエストします。しかし、別のファイルの中に記述されているファイルは、その親ファイルが届くまで見つけることができません。スタイルシート内のフォント、@importの奥にあるスタイルシート、スクリプトが追加するスクリプトがこれに該当します。階層が1つ増えるたびに、次のリクエストを開始するまでにサーバーとのラウンドトリップが1回追加されます。
別ドメインにあるファイルは、さらに長く待たされます。ブラウザはまず接続を確立(DNS、TCP、TLS)しなければならず、モバイル回線では、すでに接続が確立されている場合と比べて何倍もの時間がかかります。この歯科医院のページでは、Google FontsがHTMLから4階層下に位置しており、2つの@importを経由し、最後の2つは新しいドメイン(fonts.googleapis.com、fonts.gstatic.com)にあります。スタイルシートがfirst paintを遅らせる理由については、Render-blocking requestsで解説しています。
ツリーをフラットにするとどれだけ速くなるのか?
改善後、歯科医院のページは1秒早く描画され、独自のフォントが2秒近く早く表示されるようになりました。3つのバージョンで計測しました。「Before」は2つの@importがある状態です。「Links」は、WordPressのwp_enqueue_styleが出力するように、同じファイルをHTML内でリンクした状態です。「After」は親と子のスタイルシートを1つのファイルにまとめ、フォントを自ドメインに配置して3つすべてをpreloadし、アイコンをインラインSVGにした状態です。
| Before | Links | After | |
|---|---|---|---|
| 階層数 | 4 | 2 | 1 |
| 最も遅い 連鎖 | 4.18 | 3.25 | 1.21 |
| First paint | 2.36 | 1.43 | 1.35 |
| 全フォント | 3.57 | 2.61 | 1.72 |
| LCP | 2.36 | 1.73 | 1.96 |
時間は秒単位。スロットリングを適用したモバイル端末(Slow 4G、CPU 4倍低速化)での計測値です。階層数と最も遅い連鎖(レポートのMaximum critical path latency)は、同条件でスロットリングしたLighthouse 13.6の数値です。

Before

After
同条件でスロットリングしたモバイル端末での、読み込み開始2秒後の状態。
2階層あった@importが解消されたことで、フォントやアイコンが外部ドメインへの接続を待っている状態でも、Linksの時点でfirst paintの短縮効果の大半が得られています。LCP要素であるヒーロー画像は、修正後に0.4秒早く表示されました。LinksのLCPが最も早いのは、画像が帯域をほぼ独占できたためです。Afterではpreloadされた3つのフォントが帯域を分け合うため、修正手順ではpreloadを1〜2個に絞っています。
実際の訪問者がリクエストの連鎖で待たされているか確認するには、CoreDashでモバイルLCPをサブパーツに分解してください。到着の遅いスタイルシートやフォントは、長いrender delay(LCP画像、またはテキストの場合はfirst byteが到着した後の待機時間)として現れます。

モバイル版CoreDash、p75、LCP要素がテキストの場合:Time To First Byteに対するRender Delayを確認してください。
Preconnected originsとPreconnect candidatesは何を意味するのか?
preconnect(<link rel="preconnect">)は、ブラウザがそのドメインのファイルを必要とする前に接続を開きます。Preconnected originsにはページが事前接続したドメインが一覧表示され、Preconnect candidatesには依然として接続のセットアップを待つ必要があったドメインと、preconnectによって短縮できた見込み時間(Est LCP savings)が示されます。

ヒーロー画像が大きくlazy loadingされている同一の歯科医院ページ。Lighthouse 13.6、DevToolsスロットリング適用。
- "Unused preconnect. Only use preconnect for origins that the page is likely to request." 該当ドメインからリソースが一切読み込まれませんでした。この例ではmaps.googleapis.comとwww.youtube.comです。購入手続きなど他のテンプレートでも使われていないことを確認した上で削除してください。
- "Unused preconnect. Check that the crossorigin attribute is used properly." フォントには
crossorigin付きで開いた接続が必要ですが、スタイルシートやスクリプトには不要です。この歯科医院ページではcdnjs.cloudflare.comからFont Awesomeのスタイルシートとフォントの両方が配信されているため、スタイルシートがpreconnectを使用し、フォントは別途2つ目の接続を開いてしまいました。フォントは自ドメインでホストしてください。それが不可能な場合のみ、そのドメインに対してcrossorigin付きの2つ目のpreconnectを追加します。 - "More than 4 preconnect connections were found." preconnectを行うたびに、ページが最初に必要とするファイルと並行して接続が確立されます。自ドメインで配信できるものは自ドメインでホストし、preconnectは回避できない外部ドメインの重要ファイルのみに限定してください。
- Preconnect candidatesにあるドメイン。ファイルを自ドメインに移行してください。移行できず、かつそのファイルが重要である場合にのみ、preconnectを設定します。
Google Fontsをまだ自ドメインでホストできない場合は、HTML内でスタイルシートをリンクし、fonts.gstatic.comにcrossorigin付きでpreconnectしてください。ブラウザはリンクタグを読み込んだ時点でfonts.googleapis.comに接続します。ただし、これでも連鎖は残ります。
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> プラグインのpreconnect設定では、crossoriginが正しく処理されないことがあります。LiteSpeed CacheのDNS Preconnectはどのドメインにも付与せず、Perfmattersはチェックボックスをオンにしたドメインにのみ付与します。ページのソースコードを確認してください。crossoriginが必要なのはフォントのドメインだけです。
ネットワーク依存関係ツリーはどう修正すべきか?
まず、Lighthouseがオレンジ色で示している最も遅い連鎖の、一番深い行から着手します。その連鎖に含まれるすべてのファイルについて、「このファイルはHTML内で指定できないか?」「自ドメインから配信できないか?」を確認してください。
Google Fontsとその他のWebフォント
コードを書かずに対応する場合は、Google Fontsを自ドメインでホストする設定を有効にします。WP RocketやFlyingPressの「Self-host Google Fonts」、Perfmattersの「Local Google Fonts」、Elementorの「Load Google Fonts Locally」(設定 > パフォーマンス)、またはOMGFプラグインを使用してください。WP Rocketの設定はテーマのスタイルシート内にあるGoogle Fontsの@importを見落とすため、設定後もツリーにfonts.googleapis.comが残っている場合は、@importを直接削除します(次のセクションを参照)。LiteSpeed CacheやAutoptimizeのように、フォントローダースクリプトでGoogle Fontsを「非同期」に読み込むオプションは、連鎖の階層を1つ増やすだけです。フォントは自前でホストしてください。
手動で行う場合は、独自のスタイルシートに@font-faceルールを記述し、woff2ファイルをスタイルシートの隣のfontsフォルダに配置します:
@font-face {
font-family: "Poppins";
font-style: normal;
font-weight: 700;
font-display: swap;
src: url("fonts/poppins-v24-latin-700.woff2") format("woff2");
} フォントはスタイルシートの中でしか指定できないため、この連鎖を短縮できるのはpreloadだけです。フォントファイルの数を減らし、ファーストビューで最も大きく表示されるテキストのフォントを優先して1〜2個preloadしてください。その後LCPを確認します:
<link rel="preload" href="/wp-content/themes/acme-smile/fonts/poppins-v24-latin-700.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="/wp-content/themes/acme-smile/fonts/open-sans-v44-latin.woff2" as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="/wp-content/themes/acme-smile/style.css?ver=2.5.0"> preloadには、自ドメインであってもcrossoriginが必要です。これがないとフォントが2重にダウンロードされます。Font displayでフォントのpreloadについて解説しています。
Next.jsでは、next/fontがフォントのホストとpreloadをすでに行っています。CSSファイル内の手書きの@import url(https://fonts.googleapis.com/...)をnext/fontに置き換えてください。
@importを使用しているWordPressテーマ
親テーマからGoogle Fontsの@importを削除しても、テーマの次回アップデートで元に戻ってしまいます。テーマ内のフォント設定を探すか、テーマの開発者にフォントをenqueueするよう依頼してください。
子テーマのstyle.cssで親テーマのスタイルシートを@importすると、階層が1つ増えます。テーマの作者に@importのない子テーマを依頼するか、開発者にレポートのツリーと、@importを置き換える子テーマのfunctions.php用コードを共有してください:
add_action( 'wp_enqueue_scripts', function () {
wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
} ); 変更後はページのソースコードを確認してください。親テーマのスタイルシートは1回だけ読み込まれる必要があります。
アイコンフォント
Font AwesomeやElementorのアイコンは、すべてのアイコンをまとめたフォントを読み込むスタイルシートをロードします。Elementorでは「Inline Font Icons」を有効にしてください。スタイルシートとフォントがインラインSVGに置き換わります。それ以外の場合は、ページで使用しているアイコンをインラインSVGに置き換えるか、Font Awesomeを自ドメインでホストしてください。
Shopify
theme.liquidにGoogle Fontsのコードを貼り付けるのではなく、テーマエディタ(テーマ設定 > タイポグラフィ)でフォントを選択してください。テーマがストアの独自ドメインからフォントを配信するようになり、Dawnやその派生テーマでは自動的にpreloadも行われます。スタイルシートを追加するアプリ埋め込み(App embeds)はツリーに表示されます。1つずつオフにして、その都度Lighthouseを再実行してください。Shopifyはページのヘッダーで、自社CDNと、レンダリングをブロックしている上位3つの外部ドメインへ独自のpreconnectを送信します。Lighthouseはこれらを上限4個の対象としてカウントします。theme.liquidから古いcdn.shopify.comへのpreconnectを削除し、ツリーでまだ必要なドメインにのみ手動でpreconnectを追加してください。アプリ埋め込みを1つオフにするたびに、Shopifyのpreconnectも1つ削減できます。Shopify独自のものだけが残った状態で「More than 4 preconnect connections」が表示されても、そのままにして構いません。
スクリプトが追加するファイルと変更不可能な外部サービス
スクリプトが追加するスタイルシートは、そのスクリプトを待つことになります。ファーストビューで必要な場合はHTML内にリンクを配置し、不要な場合はスクリプトをdeferしてください。最初に実行する必要がある同意管理ツールはブロッキングのまま残ります。これが回避できない別ドメインからファイルを読み込む場合は、そのドメインにpreconnectを設定してください。サーバーでのHTML生成に時間がかかる場合は、103 Early Hintsを使用することで、HTML本体よりも前にpreconnectやフォントのpreloadを送信できます。
修正後もツリーが赤いままなのはなぜか?
Lighthouseは、HTMLがスタイルシートを1つ読み込んだ時点ですぐにこの警告を赤く表示します。そのため、連鎖が一切ないページであっても赤色のままになります。この赤色はそのまま残して構いません。HTMLと、HTML自身が指定しているファイルだけだからです。修正すべきなのは、別のファイルの下にインデントされている行です:
- 自サイトのスタイルシート配下のフォント。ファイル数を減らし、1〜2個をpreloadしてください。ファーストビューに表示されないフォントの連鎖は、そのまま残しても問題ありません。
- 外部サービスが追加するファイル。Cloudflareのメール難読化(
email-decode.min.js)やWeb Analyticsビーコン、LiteSpeed CacheのGuest Modeによるguest.vary.phpなどです。該当する機能を無効化してください。
PageSpeed Insightsの既知のバグにより、他のサイトのリクエストがツリーに混入することがあります。テストを再実行してください。

すべての連鎖を解消した歯科医院ページ。Lighthouse 13.6、DevToolsスロットリング適用。
ツリーが短縮されたことをどう確認するか?
Lighthouseを再実行し、まずは階層数と最も遅い連鎖を比較してください。Maximum critical path latencyの数値は実行ごとに多少変動します。Chrome DevToolsのネットワークパネルにあるInitiator列を見れば、どのファイルが各ファイルをリクエストしたかが分かります。実際の訪問者への影響については、次のアクセス以降のモバイルにおけるFCPとLCPをCoreDashで監視してください。Search Consoleの反映には最大28日かかります。
編集できないテーマやページビルダー、あるいは独自のフォントを読み込むアプリが最長の連鎖の原因になっていませんか?Core Web Vitals パワーアワーでは、ツリーをファイル単位で一緒に精査し、自ドメインに移すべきファイル、HTML内に記述すべきファイル、そしてpreconnectを残すべきドメインを判断します。


なぜ修正が効かないのか?
CDNがまだ古いHTMLを配信している、あるいは修正がデスクトップ用テンプレートにだけ入り、モバイルは別のテンプレートを使っている、ということがあります。URLと問題をお送りいただければ、候補の日時をご返信します。まずfield dataを確認し、1時間サイトを一緒に見て、1日以内に調査メモを書面でお送りします。€350(税別)。
URLを送る修正を実装する開発者がいませんか? サイトのコピー上で私が作業します。