font-displayとWebフォント最適化|Core Web Vitalsを改善する実践ガイド
Webフォントがパフォーマンスに与える影響
Webフォント(Google Fonts、Adobe Fontsなど)はサイトのデザイン品質を高める一方で、適切に設定しないとCore Web Vitalsのスコアを大きく悪化させる原因になります。
主な影響は2つです。
- LCP(Largest Contentful Paint)の悪化:フォントファイルの読み込みが遅いとテキストの表示がブロックされ、最大コンテンツ要素の描画が遅延する
- CLS(Cumulative Layout Shift)の悪化:フォント切り替え時にテキストサイズが変わり、レイアウトがずれる
ブログ記事やコーポレートサイトなど、テキストがメインコンテンツとなるページでは、Webフォントの設定がLCPスコアを直接的に左右します。適切に対策しないと、PageSpeed Insightsで大幅な減点を受けることになります。特に日本語サイトでは、日本語Webフォントのファイルサイズが英語フォントと比較して桁違いに大きいため、より慎重な対策が求められます。
これらの問題は font-display プロパティの正しい設定で大幅に改善できます。
font-displayとは
font-display は、Webフォントの読み込み中にブラウザがどのようにテキストを表示するかを制御するCSSプロパティです。
@font-face {
font-family: 'Noto Sans JP';
src: url('/fonts/NotoSansJP-Regular.woff2') format('woff2');
font-display: swap;
}
このプロパティを設定しないと、ブラウザはデフォルトの動作(多くの場合、フォント読み込み完了までテキストを非表示にする)を行います。これがLCP悪化の最も一般的な原因のひとつです。
font-displayの5つの値
| 値 | 動作 | LCPへの影響 | CLSへの影響 |
|---|---|---|---|
auto | ブラウザのデフォルト動作(多くの場合blockと同じ) | 悪い | 低い |
block | フォント読み込みまでテキスト非表示(最大3秒) | 悪い | 低い |
swap | 代替フォントで即表示→読み込み後にWebフォントへ切り替え | 良い | やや高い |
fallback | 100msだけ非表示→代替フォント表示→短い切り替え期間 | 良い | 低い |
optional | 100msだけ非表示→間に合えばWebフォント使用、間に合わなければ代替のまま | 最良 | 最低 |
block と auto はテキストが最大3秒間見えなくなる、いわゆる「FOIT(Flash of Invisible Text)」を引き起こします。一方、swap は代替フォントで即座にテキストを表示するため、「FOUT(Flash of Unstyled Text)」が発生しますが、LCPへの影響は最小限です。多くの場合、ユーザーがFOUTに気づくのは一瞬であり、テキストが3秒間見えないFOITと比較すれば、ユーザー体験への悪影響は格段に小さいです。
Googleが推奨する設定
Googleは**font-display: swap** を推奨しています。PageSpeed InsightsやLighthouseでも、この設定がない場合は「Ensure text remains visible during webfont load(Webフォントの読み込み中にテキストが表示されるようにしてください)」という警告が表示されます。
swapの主なメリットは、Webフォントが読み込まれる前でもテキストが即座に表示されることです。これによりLCPが劇的に改善します。テキストが最大コンテンツ要素であるページ(ほとんどのブログ、ドキュメントサイト、コーポレートサイトが該当)では特に大きな効果が得られます。
トレードオフとして、ブラウザが代替フォントからWebフォントに切り替える際にわずかなCLSが発生する可能性があります。これは後述するsize-adjustで軽減できます。
Google Fontsの最適な読み込み方
ステップ1:display=swapパラメータを追加
Google FontsのURLに&display=swapを追加するだけで、font-display: swapが適用されます。
<!-- NG: displayパラメータなし -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700" rel="stylesheet">
<!-- OK: display=swap を追加 -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet">
この1行の変更だけでPageSpeed Insightsの警告を解消でき、LCPスコアが大幅に改善されるケースが多いです。既存サイトのフォント最適化で最も費用対効果の高い修正のひとつです。
ステップ2:preconnectヒントを追加
Google Fontsのドメインへの接続を事前に確立することで、レイテンシを削減しフォントの読み込み開始を早められます。
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet">
preconnect はDNS解決、TCP接続、TLSハンドシェイクを事前に完了させるため、フォントのCSSファイルをリクエストする時点でのレイテンシが大幅に削減されます。Google Fontsではフォントのメタデータ(fonts.googleapis.com)とフォントファイル本体(fonts.gstatic.com)が別ドメインにあるため、両方にpreconnectを設定するのが効果的です。
ステップ3:セルフホスティングで最速化
フォントファイルを自サーバーに配置する方法が最もパフォーマンスに優れます。外部ドメインへのリクエストが不要になり、キャッシュ制御も完全にコントロールできます。
@font-face {
font-family: 'Noto Sans JP';
src: url('/fonts/NotoSansJP-Regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
Next.jsではnext/fontモジュールを使うことで、ビルド時にフォントが自動的にセルフホスティングされ、最適なfont-display設定も適用されます。
import { Noto_Sans_JP } from 'next/font/google';
const notoSansJP = Noto_Sans_JP({
subsets: ['latin'],
weight: ['400', '700'],
display: 'swap',
});
CLSを防ぐ:size-adjustによるフォントマッチング
font-display: swapを使うと、代替フォントからWebフォントへの切り替え時にCLSが発生することがあります。これは2つのフォントの文字メトリクス(文字幅、高さ、行間隔)が異なるためです。size-adjustプロパティを使って代替フォントを調整し、Webフォントとの差を最小化できます。
@font-face {
font-family: 'Adjusted Arial';
src: local('Arial');
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
body {
font-family: 'Noto Sans JP', 'Adjusted Arial', sans-serif;
}
size-adjust は代替フォントの全体的なサイズを調整し、ascent-override、descent-override、line-gap-override はフォントの垂直方向のメトリクスを微調整します。これらの値を適切に設定することで、代替フォントとWebフォントのレイアウト上の差異がほぼゼロになり、CLS(レイアウトシフト)を事実上解消できます。
手動でこれらの値を計算するのは非常に手間がかかります。以下のツールが自動で計算してくれます。
- Fontaine — Next.jsやNuxtと統合できるライブラリ
- next/font — Next.jsの組み込みフォント機能がGoogle Fontsに対して自動的に
size-adjustを適用
Next.jsを使っている場合はnext/fontだけでsize-adjustの問題が解決するため、手動で計算する必要はほぼありません。他のフレームワークを使っている場合はFontaineが便利です。
読み込むフォントウェイトを最小限に
読み込むフォントウェイトが増えるほど、ダウンロードサイズが増加しLCPが悪化します。
<!-- NG: 使わないウェイトまで読み込んでいる -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@100;200;300;400;500;600;700;800;900&display=swap" rel="stylesheet">
<!-- OK: 実際に使うウェイトだけ指定 -->
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet">
目安: ほとんどのサイトでは2〜3ウェイト(Regular + Bold、必要に応じてMedium)で十分です。9ウェイトすべてを読み込むと、特に日本語フォントではダウンロードサイズが数MBに膨れ上がることがあります。デザイナーと相談して、サイト全体で実際に使用しているフォントウェイトを棚卸しし、不要なウェイトの読み込みを削除するのが効果的です。
重要なフォントのプリロード
ファーストビュー(初期表示領域)に表示されるフォントについては、プリロードによってブラウザに即座にダウンロードを開始するよう指示できます。
<link rel="preload" href="/fonts/NotoSansJP-Regular.woff2" as="font" type="font/woff2" crossorigin>
注意: 実際にファーストビューで使用するフォントだけをプリロードしてください。使わないフォントのプリロードは帯域を浪費し、画像やCSSなど他の重要なリソースと帯域を奪い合うことで、かえってパフォーマンスを悪化させる可能性があります。通常はプリロードするフォントファイルは1〜2個に抑えるのが適切です。
改善効果の確認方法
フォント最適化の効果は以下のツールで確認できます。
- PageSpeed Insights — LCPとCLSのスコアを確認し、「Ensure text remains visible during webfont load」の警告が解消されたかチェック
- Chrome DevTools > Performance — タイムライン上でフォントの読み込みタイミングを可視化
- Chrome DevTools > Network — フォントファイルのサイズと読み込み時間を確認。「Font」でフィルタリングすると見やすい
- IndexReady — URLを入力するだけでCore Web Vitalsスコアとパフォーマンス項目を自動採点
よくある質問
font-display: swapとoptionalどちらが良いですか?
ブランドフォントの表示を重視するならswapが適しています。Webフォントが最終的に必ず表示されることを保証します。パフォーマンスが絶対的な最優先事項であるならoptionalを検討してください。optionalは低速な接続ではWebフォントを完全にスキップする可能性があるため、CLSはゼロになりますがWebフォントが表示されないことがあります。ほとんどのWebサイトにとっては、swapが最もバランスの良い選択です。
next/fontを使えばfont-displayの設定は不要ですか?
はい。next/fontはデフォルトでfont-display: swapを適用し、ビルド時にフォントファイルをセルフホスティングし、size-adjustの値も自動計算してCLSを最小化します。Next.jsプロジェクトではnext/fontを使用するのが最も簡単で効果的なアプローチです。
日本語(CJK)フォントは英語フォントより重いですか?
大幅に重くなります。日本語フォントは数千のグリフを含むため、ファイルサイズが英語フォントの10〜20倍になることがあります。Google Fontsの日本語フォントは最適化されたサブセットで配信されますが、それでもウェイト数を最小限に抑えることが重要です。サブセット処理なしだと、日本語フォント1ウェイトだけで1MBを超えることもあります。
すべてのフォントをプリロードすべきですか?
いいえ。ファーストビューに表示される重要なフォントだけをプリロードしてください。過剰なプリロードは、画像やCSSなど他の重要なリソースと帯域を奪い合い、逆にパフォーマンスを悪化させます。通常は1〜2個のフォントファイルをプリロードすれば十分です。
font-displayが正しく機能しているか確認する方法は?
Chrome DevToolsを開き、Networkタブで「Font」でフィルタリングします。ページをリロードして動作を観察してください。swapが正しく設定されていれば、テキストはまずシステムフォントで即座に表示され、その後Webフォントに切り替わります。ネットワークを「Slow 3G」にスロットリングすると、切り替わりの動作がより明確に確認できます。