Lighthouseの「Font display」:警告対象と修正方法
Lighthouse 13ではfallbackも警告対象になりました。swapでもレイアウトシフトは発生します。フォントに手間をかける価値があるのはどのような場合でしょうか。
font-displayの警告でスコアは下がりますか?
Lighthouseは、font-display: block、auto、fallbackで読み込まれるすべてのWebフォントに対して、「Font display」インサイト(「テキストが常に表示されるよう、font-displayにswapまたはoptionalの設定を検討してください」)で警告を出します。これはLighthouse 13以前は「Webフォント読み込み中のテキストの表示」と呼ばれていた監査項目です。このインサイト自体にスコアの配点はありません。しかし、見出しがLCP要素の場合、非表示にすることでモバイルでのLCPが遅延します。訪問者が最初に目にするフォントにはswapを指定し、metric overridesでfallbackのサイズを合わせてください。
「Font display」インサイトは何をチェックしていますか?
Lighthouse 13およびPageSpeed Insightsでは、このインサイトに「テキストが常に表示されるよう、font-displayにswapまたはoptionalの設定を検討してください。swapはfont metric overridesによってレイアウトシフトを抑えるようさらに最適化できます」と表示されます。Lighthouse 13以前、この監査項目は「Webフォント読み込み中のテキストの表示」と呼ばれていました。
Lighthouseは、ページ読み込み時にChrome自身が記録したトレースを読み取ります。トレースには、ダウンロードが開始された各Webフォントに対してChromeが使用したfont-displayの値が記録されています。このインサイトが警告対象とするのは、次の3つの値です。
block: フォントのダウンロード中、最長3秒間テキストが非表示になります。auto: 値が指定されていない状態です。Google Fontsで&display=を指定しない場合や、古いテーマ、Font Awesome 4、Material Iconsでこの値になります。fallback: テキストが非表示になる時間は100ミリ秒だけです。それでもLighthouse 13は警告を出します。
合格するのは swap と optional の2つの値だけです。これはLighthouse 13で変更されました。以前の監査では block と fallback も合格していたため、何年も前に fallback で「修正」したサイトにも再び警告が表示されます。WordPressのブロックテーマはデフォルトで fallback を使用しており、Font Awesome 5と6は block を使用しています。
「Est savings」はトレース内でフォントのリクエストにかかった時間で、上限は3,000msです。PageSpeed Insightsはスロットリングなしでトレースを記録するため、そこでは小さな数値が表示されることがよくあります。下のレポートは、長体見出しフォントを使用したアウトドアショップの商品ページ(テストページ)を、DevToolsのスロットリング(Slow 4G)を適用したモバイル端末で計測したものです。そこでは本文フォントの読み込みに3秒以上かかったため、表には上限値が表示されています。どちらにせよ、その時間を丸ごと取り戻せるわけではありません。fallbackでテキストが隠れるのは最長でも100ミリ秒ですし、autoではナビゲーション開始から2秒後にChromeがフォントの待機を打ち切るからです。

説明の隣に、Lighthouseは2つのラベルを表示します。FCPは、Lighthouseが短縮できると見なしている指標です。Unscoredは配点がゼロであることを意味し、このインサイト自体がスコアを変動させることはありません。blockが指定されたフォントがスコアに現れるのは、Speed IndexとLCPを通じてです。
どこでも使用されていない@font-faceルールでこの警告が出ることはありません。また、Lighthouseはトレースを読み取るため、Typekitのキットやプラグインが読み込むGoogle Fontsなど、自身で直接追加していないフォントもリストアップされます。以前の監査では、別ドメインのフォントに対して「unable to check」と表示されていました。
Webフォントの読み込み中、ブラウザでは何が起きていますか?
ブラウザは、表示される要素がそのフォントを必要としていると判明するまで、フォントをリクエストできません。HTMLを取得し、CSSを取得し、「この見出しはBarlow Condensedを使用している」というスタイル計算が行われて初めて、フォントのリクエストが開始されます。スロットリング環境のモバイル端末では、HTMLとCSSを受信した後の0.74秒時点でした。フォントの検出はどうしても遅くなります。preloadはその開始を前倒しするだけで、フォントにはすでに最高優先度(highest priority)が割り当てられています。
その瞬間から、訪問者に何が表示されるかはfont-displayの値によって決まります。ブラウザのソースコードにおけるタイミングは以下の通りです。
| 値 | Chromeで訪問者に表示される内容 |
|---|---|
block | フォントリクエストから最長3秒間テキストが非表示 |
auto | blockと同様。ただしナビゲーション開始から2秒を超えることはない。Chromeが回線を3G以下と判定した場合は即座にfallbackを表示 |
swap | 即座にfallbackを表示し、Webフォントが到着したら切り替え |
fallback | 100ミリ秒間テキストが非表示。3秒を超えて到着したフォントはそのページでは適用されない |
optional | 即座にfallbackを表示。初回レンダリングまでに間に合った場合のみWebフォントを適用 |
SafariとFirefoxも、blockとautoでは最長3秒間テキストを非表示にします。Firefoxはフォントの75%がダウンロード済みの場合、さらに1.5秒長く待機します。両ブラウザともfallbackとoptionalでは100ミリ秒間テキストを隠し、Firefoxはswapでも同様の動作をします。
Chromeでは、blockはautoよりも遅くなります。autoには2秒の上限がありますが、blockにはないためです。また、Chromeのoptionalには100ミリ秒の猶予期間がありません。preloadを指定しない場合、高速なサーバーから配信しても初回レンダリングにはまず間に合いません。preloadを指定していれば、ページがレンダリング可能になるタイミングから約100ミリ秒以内に届く場合に限り間に合います。キャッシュが効いている次のページなら確実に間に合います。

初回ペイント時の font-display: block

初回ペイント時の font-display: swap
スロットリング環境のモバイル端末における初回ペイント時(0.9秒)の商品ページ。黒い矩形は写真で、どちらも読み込み中です。corewebvitals.io上のテストページ、Chrome 155、端末幅412px、Slow 4G、CPU 4倍減速。
blockでは、初回ペイント時にヘッダー、パンくずリスト、星評価が表示され、商品名が入る部分は空白のままです。見出しフォントはサイズが小さく(15kB)、1.7秒で到着します。本文フォントは344kBあり、Chromeが待機を打ち切る3.7秒の時点でもまだダウンロード中のため、それまでは写真の下に何も表示されません。swapを指定すると、商品名と商品説明が初回ペイント時から読める状態になります。

block適用時(3秒後)

swap適用時(3秒後)
3秒後の同ページ:見出しフォントと写真は表示されていますが、本文フォントはまだ届いていません。
font-displayはLCP、CLS、FCPに影響しますか?
LCP
非表示のテキストはLCP要素になり得ません。blockやautoでは、テキストが表示された時点(フォントが到着した時、またはblock期間が終了した時)にテキストのLCPが記録されます。LCP要素が見出しや段落であるページでは、blockによってLCPが最大3秒遅くなる可能性があります。autoの場合、Chromeでの遅延はそれより短く、Slow 4G環境では即座にArialでテキストが表示されました。swapの場合、LCPはfallbackフォントでの描画時点で確定し、その後Webフォントに切り替わってテキストのサイズが大きくなったとしても、新たなLCPエントリが追加されることはありません。
上記の商品ページではどのバージョンでも写真がLCP要素となっているため、font-displayによるLCPの変動はありませんでした。各自のページでまず確認すべきなのはこの点です。LCP要素はテキストか、それとも画像でしょうか?同じLighthouseレポート内の「LCP breakdown」インサイトで特定できます。
CLS
テキストの占有領域が変わるswapが発生すると、それ以降のすべての要素が押し出されます。これはblockやautoでも同様です。非表示のテキストもfallbackフォント分の領域を占有するため、Webフォントへの切り替え時にまったく同じズレが生じます。block、auto、swapのいずれのバージョンでも、見出しフォントが到着した瞬間にCLS 0.031が記録されました。

swap適用・変更前:Arialで3行表示

swap適用・変更後:2行に変化
通常のswapでは、1.7秒で見出しフォント(Barlow Condensed)が到着すると見出しが3行から2行に縮みます。その下のすべての要素が39px上に移動し、CLS 0.031が発生します。破線の枠線は移動前の写真の位置です。

metric overrides適用・到着前:Arial Boldで2行表示

metric overrides適用・到着後:2行のまま変化なし
Arial BoldをBarlowの幅に合わせて縮小(size-adjust: 68.32%)したfallbackフォントを適用した同ページ。初回ペイント時から見出しが2行で収まり、一切ズレが発生しないためCLSは0になります。
つまり、swapを使えば「Font display」インサイトには合格しますが、レイアウトシフトは残ったままになります。0.031は基準値の0.1未満ですが、実際の商品ページでは遅れて届く2つ目のフォント、別フォントで描画される価格、追従ヘッダー(sticky bar)などが積み重なる可能性があります。fallbackへのmetric overridesを適用すれば、このシフトを抑えられます。
Lighthouseはフォントが原因だとは教えてくれません。swapバージョンの「Layout shift culprits」では、写真が「Unsized image element」として指摘されています。しかし、この画像にはwidthとheightが指定されています。実際に画像を動かしたのは、まさにその瞬間に到着した見出しフォントです。すでに設定されている画像寸法を探し回る前に、レイアウトシフトの発生時刻とフォントリクエストのタイミングを突き合わせて確認してください。

FCP
Lighthouseは削減効果をFCPとしてレポートします。しかし、ほとんどのページでは別の要素によってFCPが決まります。この商品ページではヘッダーや送料無料バーにシステムフォントが使われており、blockでもswapでも同様に0.8秒で描画されます。ページ上にWebフォントのテキストしか存在しない環境でテストした際も、Chrome 155はテキストが非表示のまま112ミリ秒時点でFCPを記録しました。Chromeはテキストを描画済みと見なし、グリフの描画のみをスキップしているためです。したがって、LighthouseがFCPの短縮効果として提示する時間は、実際のFCPには反映されません。blockによって失われるのは、テキスト要素のLCP、Speed Index、そして訪問者への視覚的な表示です。
どれくらいのサイトに警告が出ていて、どのような場合に無視できますか?
State of CWVがWebフォントを宣言している170,706サイトのホームページを対象に@font-faceルールを調査したところ、フォントが読み込まれた場合に半数のルールで警告がトリガーされる状態でした。39.7%は値の指定がなく(auto)、9.6%はblock、0.9%はfallbackを使用しています。optionalの値をどこかに使用しているサイトは、わずか471サイトにとどまります。

モバイル端末で良好なLCPを記録したサイトの割合。ホームページが読み込むフォントファイル数と、@font-faceルール内のfont-displayの値別に分類。State of CWV、2026年10月:Webフォントを宣言している170,706サイト、モバイルでのCrUX p75、良好なLCPは2.5秒以下。
フォントファイルが1〜2個の場合、差はほとんどありません。swapまたはoptionalのみのサイトの88%がモバイルで良好なLCPを維持しているのに対し、block、auto、fallbackのみのサイトでも87%です。フォントファイルが6〜10個になると差は6ポイントに開き、11個以上では9ポイントになります。最も成績が悪いのは、両方の種類を混在させているサイトです。そうしたサイトは宣言しているフォントが極めて多く、中央値で44個の@font-faceルールが存在します(通常グループは18個)。テーマのフォント、プラグインのフォント、アイコンフォントが重なっていると考えられます。なお、CLSはグループ間でほとんど差がありません。
ただし、これは相関関係です。フォントに気を配っているサイトは、通常ほかのすべての要素にも気を配っています。前述したブラウザの挙動も考慮したうえでの私のルールは、「まずフォントファイルを削減し、その後にfont-displayを設定する」です。
以下のケースでは、警告を放置しても問題ありません。
- フッターやレビューなど、フォントの用途がファーストビュー外のテキストだけに限られている場合
- LCP要素が画像で、フォントによるズレ(シフト)が発生していない場合
field dataでフォントの問題をどう見つけますか?
Lighthouseが測定するのは、シミュレートされた1台の端末による1回の読み込みに過ぎません。実際の訪問者の回線状況は千差万別であり、再訪者であればフォントがキャッシュに残っています。CoreDashでは、2つの内訳データによってフォントがパフォーマンスの損失につながっているかを確認できます。
- 要素別のLCP:モバイルでのLCP要素が見出しや段落の場合、blockやautoが指定されたフォントは、フォントを待つすべてのアクセスでLCPを遅延させます。画像であれば、フォントがLCPに影響することはありません。
- 要素別のCLS:フォントのswapは、写真、後続のセクション、購入ボタンなど、テキストの下にある要素を動かします。CoreDashは移動した要素を特定します。ただし、フォントが原因だと直接表示するわけではありません。動いた要素が見出しや段落の直下に位置し、幅と高さ(widthとheight)が指定されているなら、フォントのswapが原因の可能性が高いです。
CrUXでも、オリジンまたは特定のURLについて過去28日間のp75の同じ指標を確認できますが、要素への帰属(attribution)情報は得られません。

要素別のLCP

要素別のCLS
実在するショップ(acme-pagespeed.com)におけるCoreDashのデータ(モバイル、p75)。商品タイトルが他のどの要素よりも多くのセッションでLCP要素となっており、LCPは3.28秒でした。商品写真がLCP要素の場合、LCPは2.21秒です。CLSの表では、タイトル直下にあるその写真が最上位に並び、1,214セッションで0.07を記録しています。評価は依然として「良好」ですが、これほど多くのセッションで移動している要素は他にありません。
DevToolsで警告対象のフォントを見つける方法
Chromeでページを開き、Performanceパネルに移動して、ネットワークをSlow 4G、CPUを4倍減速(4x slowdown)に設定し、再読み込みを記録します。Insightsサイドバーの「Font display」に、警告対象となったすべてのフォントが一覧表示されます。それをクリックすると、DevToolsのNetworkトラック上で該当するフォントリクエストが枠線で強調表示されます。

次に、各フォントリクエストの終了位置、LCPマーカーの位置、そしてフォントの読み込み終了直後にLayout shiftsトラックでシフトが発生していないかを確認します。
警告されたファイルを指定しているすべての@font-faceを見つけるには、Sourcesパネルを開き、全ファイル検索(MacではCmd+Option+F、WindowsではCtrl+Shift+F)でファイル名を検索して、見つかった各ルールに適切な値を設定します。
「Font display」インサイトの警告を解決する方法
Lighthouseの表にあるフォントのURLから配信元が分かります。それによって、どこでfont-displayを設定すべきか、あるいはそもそも設定可能なのかが決まります。
自サイトの @font-face
自ドメイン上にあり、URLに/wp-content/、/cdn/fonts/、/_next/が含まれていないフォントは、自身が作成したCSSから読み込まれています。そのフォントのすべての@font-faceルール(2枚目のスタイルシートにある重複分も含め)にfont-display: swapを追加してください。例外はアイコンフォントです(後述)。
@font-face {
font-family: "Barlow Condensed";
src: url(/fonts/barlow-condensed-700.woff2) format("woff2");
font-weight: 700;
font-display: swap;
} Google Fonts
表にはfonts.gstatic.comと表示されますが、設定はフォントを読み込むfonts.googleapis.com/css2のリンク側で行います。URLに&display=swapを追加してください。
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@700&display=swap"> さらに高速化したいなら、フォントをセルフホストするのが得策です。余計な接続が不要になり、preloadも自身で制御できます。
Adobe Fonts
use.typekit.netから読み込まれるフォントのfont-displayは、fonts.adobe.comのWebプロジェクト側で設定します。「プロジェクトを編集」を選択し、サイドバーで指定してください。Adobeのデフォルトはautoで、URLにパラメータを付与しても反映されません。
WordPress
テーマのフォントは、URLに/wp-content/themes/が含まれています。ブロックテーマでは、theme.json内でフォントフェイスごとにfontDisplayを設定します。
"fontFace": [{
"fontFamily": "Barlow Condensed",
"fontWeight": "700",
"fontStyle": "normal",
"fontDisplay": "swap",
"src": ["file:./assets/fonts/barlow-condensed-700.woff2"]
}] クラシックテーマの場合は、wp_enqueue_styleで指定しているGoogle FontsのURLに&display=swapを追加するか、テーマ自体の@font-faceルールにfont-displayを記述します。/wp-content/plugins/配下のフォントはプラグインやページビルダーによるものです。まずは該当プラグインの設定画面でフォント設定を探してください。ページビルダーが読み込むGoogle Fontsについては、Elementorなら「Elementor」→「設定」→「詳細」タブにある「Googleフォントの読み込み(Google Fonts Load)」で設定できます。プラグインのOMGFを使えば、Google Fontsをローカルホストしたうえで強制的にswapを適用できます。フォントやCSSに関するそのほかの対応手順は、WordPressガイドにまとめてあります。
Shopify
Shopifyテーマのフォントは、ショップのドメイン下でURLに/cdn/fonts/が含まれます。これらはtheme.liquid内のfont_faceフィルター経由で読み込まれますが、font_displayを指定しないとfont-display自体が出力されません。
{{ settings.type_header_font | font_face: font_display: 'swap' }} Dawnテーマではすでにこれが設定されています。
Next.js
next/fontはデフォルトでdisplay: 'swap'を使用し、フォントをpreloadしたうえでmetric overridesを用いたfallback(adjustFontFallback)を自動生成します。このフォントはURLに/_next/static/media/を含みます。このパスを持つフォントで警告が出ている場合は、next/fontの呼び出し側で別の値(display: 'block'など)が明示的に指定されているため、そこを修正してください。このパスを含まない警告フォントは、レイアウト内でのGoogle Fontsへの<link>や、コンポーネントライブラリのCSSファイルなど、別の方法で読み込まれています。
変更できない、または変更すべきでないフォント
- アイコンフォント(
fa-solid-900.woff2、bootstrap-icons.woff2、eicons.woff2):swapを指定すると、アイコンが表示されるべき場所に文字や空の四角が表示されてしまいます。可能であればアイコンフォントをSVGに置き換えてください。それが無理ならblockのままにしておきます。 - フォント設定を持たないプラグインやアプリ(WordPressプラグイン、Shopifyアプリが追加するフォントなど):開発元に連絡してswapを設定するよう要望してください。
- ページにフォントを追加するサードパーティ製スクリプト(ベンダーのドメインから配信):こちら側では制御できません。ページのレンダリング完了後にスクリプトを読み込むか、該当の警告はそのままにしておきます。
フォントファイル数を減らす
使用していない太さ(ウェイト)やスタイルを削除し、6つの静的ファイルの代わりに1つのバリアブルフォントを使用してください。フォントファイルを1つ削るごとに、リクエストが1つ減り、swapが1つ減り、このインサイトに表示される行が1つ減ります。
swapとoptionalのどちらを使うべきか?
swap | optional | |
|---|---|---|
| テキストの非表示 | なし | なし |
| レイアウトシフト | あり(fallbackを調整しない場合) | なし |
| 低速な初回訪問でのWebフォント | 適用される(遅延あり) | 適用されない(そのページではfallbackを維持) |
| 次のページでのWebフォント | 適用される(キャッシュから) | 適用される(キャッシュから) |
見出しやロゴなど、ブランドを印象付けるフォントには、fallbackを調整したうえでswapを使用します。システムフォントでも十分な本文テキストにはoptionalを使用し、初回ページでも適用される可能性を高めるためにそのフォントをpreloadしてください。
<link rel="preload" href="/fonts/inter-var.woff2" as="font" type="font/woff2" crossorigin>
<style>
@font-face {
font-family: "Inter";
src: url(/fonts/inter-var.woff2) format("woff2");
font-weight: 100 900;
font-display: optional;
}
</style> 自ドメインのフォントであっても、crossorigin属性は必須です。これがないと、ブラウザはフォントを2回ダウンロードしてしまいます。Chromeでのフォントのpreloadは、初回レンダリングを最長100ミリ秒遅らせる可能性があるため、preloadするフォントは1〜2個にとどめ、決してすべてのフォントをpreloadしないでください。Slow 4G環境では、preloadしたフォントであっても初回ペイント後に到着したため、ページはfallbackを表示し続けました。
metric overridesでレイアウトシフトを防ぐ
fallbackフォントのサイズをWebフォントのサイズに合わせます。これを行うには、ローカルフォントを参照してスケーリングする2つ目の@font-faceを定義します。
@font-face {
font-family: "Barlow Fallback Arial";
src: local("Arial Bold"), local("Arial-BoldMT");
font-weight: 700;
size-adjust: 68.32%;
ascent-override: 146.37%;
descent-override: 29.27%;
line-gap-override: 0%;
}
h1 {
font-family: "Barlow Condensed", "Barlow Fallback Arial", Arial, sans-serif;
} size-adjustは、Webフォントでのテキスト幅をfallbackフォントでの幅で割った値です。ascent-overrideとdescent-overrideは、Webフォント自身のアセント(ascent)とディセント(descent)を同じsize-adjustで割った値です。FontaineやCapsizeなどのツールを使えば、フォントファイルからこれらを自動計算できます。
本文フォントも同様ですが、モバイルの画面幅と実際に使用するフォントサイズにおいて、実際のテキストで計測する必要があります。Interはフォントサイズによって幅が変わります。見出しサイズではArialの約98%ですが、18pxでは約105%になります。size-adjustを97.6%に設定した場合、Interでは6行になる商品説明がfallbackでは5行で折り返され、購入ボタンが動いてしまいました。101%にすると両者の折り返しが一致します。確認するには、DevToolsでフォントファイルをブロックし(Networkパネルで右クリック、「Block request URL」を選択)、モバイル幅で再読み込みして通常の読み込み時と改行位置を比較します。一致するまでsize-adjustの値を調整してください。
local()が検出できるのは、端末にインストールされているフォントだけです。ArialはWindows、macOS、iPhoneに搭載されていますが、Android端末にはRobotoが搭載されています。Androidの訪問者向けには、固有の数値を設定したRoboto用の2つ目のfallback用フォントフェイスを追加してください。
h1 {
font-family: "Barlow Condensed", "Barlow Fallback Arial", "Barlow Fallback Roboto", sans-serif;
} local()はインストールされていないフォントをスキップするため、各端末は利用可能な最初のフォントを適用します。Safariはsize-adjustをサポートしていますが、ascentとdescentのoverrideにはまだ対応していません。そのためSafariでは幅は一致しますが、line-height: normalの場合に行の高さがわずかに異なる場合があります。WordPressやShopifyにはこうした設定機能が一切ありません。開発者による実装が必要です。
修正が効いたことを確認する方法
モバイルで再度Lighthouseを実行します。「Font display」が合格したインサイト(passed insights)に移動しているはずです。この商品ページでは、配点のある指標の改善によりスコアが97から98に向上しました。テキストが早く表示されるようになったことでSpeed Indexが1.9秒から1.3秒に短縮され、overridesによってCLSが0.031から0に改善したためです。次に、自身のレポートでCLSを確認してください。フォント到着時にページがまだ動く場合は、fallbackにmetric overridesが必要です。

修正前:font-display: block

修正後:swapとmetric overrides
Lighthouse 13.5.0、モバイル、DevToolsスロットリング。
optionalを選択した場合、Lighthouseのスクリーンショットには通常fallbackフォントが表示されます。Lighthouseは初回アクセス(cold load)でページを読み込むため、これはoptionalが設計通りに機能している証拠です。
CoreDashでは、次回の訪問以降、端末ごとの効果が即座に反映されます。CrUXとSearch Consoleは過去28日間の集計を表示するため、修正から2週間が経過した時点でも、表示されるデータの半分は修正前の古いサイトのものです。
モバイルのLCPやCLSが赤色(不良)のままの原因がフォントにあるか確認したいですか?Core Web Vitals power hourでは、field dataとページのトレースを一緒に確認し、テーマ内のどのフォントルールを修正すべきかを明確にします。