ストアのメニューにぴったりのタイプフェイスを選ぶのに何時間も費やしました。メニューラベルにはブランドに完全にマッチするカスタムサンセリフフォントが使われています。ところが、モバイルでストアをテストするたびに、メニューがあるべき場所にテキストが見えない状態が表示され、その後フォントが読み込まれるとレイアウトが移動します。CLSスコアは0.18で、Googleは「改善が必要」と評価しており、メニューフォントが原因だと疑っています。
問題はフォント自体ではありません。問題はブラウザがフォント読み込みを処理する方法です。デフォルトでは、ほとんどのブラウザはカスタムフォントがダウンロード完了するまでテキストを隠します。これには遅い モバイル接続では300~800ミリ秒かかる可能性があります。メニュー領域は空のままになり、ページが壊れているように見え、フォントが最後に表示されると、その下にあるすべてが移動します。これはLCP(重要なコンテンツが遅延するため)とCLS(レイアウトが移動するため)の両方に影響します。
この記事では、5つのfont-displayストラテジーを説明します。ナビゲーションメニューに最適なもの、およびCore Web Vitalsを壊さないフォント読み込みの実装方法を紹介します。
- ブラウザはフォントダウンロード中にデフォルトでテキストを隠し、Flash of Invisible Text(FOIT)を引き起こします。
font-displayは、テキストをすぐに表示するか、カスタムフォントを待つかを制御します。font-display: swapはメニューテキストに最適な選択—フォールバックをすぐに表示し、準備ができたら交換します。- システムフォント(デバイスに既にインストールされているフォント)は読み込みコストがゼロで、FOIT/FOUTのリスクを完全に排除します。
- フォントプリロードは遅延を削減できますが、レイアウトシフトのリスクを完全に排除することはできません。
2つのフォント読み込み問題:FOITとFOUT
ブラウザがカスタムウェブフォントに遭遇すると、フォントファイルがまだダウンロード中に、そのフォントを使用するテキストをどうするかを決定する必要があります。2つの可能な動作があり、それぞれにトレードオフがあります。
Flash of Invisible Text(FOIT)
ブラウザはフォントが読み込まれるまでテキストを隠します。テキストスペースは予約されていますが、何も表示されません。フォントのダウンロードに500ミリ秒かかる場合、ユーザーは半秒間空の空間を見つめています。これはほとんどのブラウザのデフォルト動作です。
FOITはLCPに悪いです。重要なテキストコンテンツがフォント読み込みまで表示されないためです。また、ユーザビリティにも悪いです—ユーザーはメニューを読むことができず、ページが壊れていると思うかもしれません。
Flash of Unstyled Text(FOUT)
ブラウザはフォールバックフォント(通常はArialやHelveticaなどのシステムフォント)を使用してテキストをすぐに表示し、読み込まれたらカスタムフォントに交換します。テキストはすぐに読み取り可能ですが、フォールバックフォントとカスタムフォントの寸法が異なる場合、交換時にレイアウトシフトが発生する可能性があります。
FOUTはLCPに良いです(テキストがすぐに表示されるため)が、慎重に処理しないとCLSに悪影響を与える可能性があります。重要なのは、フォールバックフォントの寸法をカスタムフォントにできるだけ合わせることです。
5つのfont-displayストラテジー
font-display CSSプロパティは、ブラウザがフォント読み込み期間を処理する方法を制御します。5つの可能な値があり、それぞれ異なるタイミングとフォールバック動作を持っています。
| 値 | 動作 | 最適な用途 |
|---|---|---|
auto |
ブラウザが決定(通常は3秒間のFOIT、その後FOUT) | 推奨されない—予測不可能 |
block |
最大3秒間FOIT、その後交換 | ブランドフォントが重要な装飾的テキスト |
swap |
すぐにFOUT—フォールバックを表示、準備ができたら交換 | 本文、ナビゲーションメニュー |
fallback |
100msのFOIT、その後3秒のFOUT、その後フォールバックを維持 | フォントが重要だが速度も重要な見出し |
optional |
100msのFOIT、フォント準備完了時間がない場合フォールバック、交換なし | パフォーマンスが重要なテキスト |
ナビゲーションメニューの場合、font-display: swapはほぼ常に正しい選択です。メニューをすぐに読み取り可能にし(LCPとユーザビリティに良い)、読み込まれたらすぐにブランドフォントに交換します(ブランド一貫性に良い)。リスクはレイアウトシフトで、これについては後で説明します。
スタイルシートでfont-displayを使用する方法
フォントが@font-faceを使用してCSSで定義されている場合は、font-displayプロパティを追加します:
@font-face {
font-family: 'BrandFont';
src: url('/fonts/brandfont.woff2') format('woff2');
font-display: swap;
}
.menu-link {
font-family: 'BrandFont', -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
}
font-familyスタックが重要です。カスタムフォントをまず最初にリストして、その後システムフォントをフォールバックとしてリストします。これでメニューテキストがシステムフォントで即座に表示され、読み込まれたらカスタムフォントに交換されます。
フォントがGoogle Fontsから読み込まれる場合は、URLにdisplay=swapパラメータを追加します:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap">
Google Fontsは生成されたCSSに自動的にfont-display: swapを注入します。
フォールバックフォントマッチングでレイアウトシフトを防ぐ
font-display: swapの問題は、フォールバックフォントとカスタムフォントのサイズや間隔が異なる場合、交換時にテキストが再フローし、レイアウトシフトが発生することです。これはナビゲーションメニューでは特に顕著です。わずかなシフトでもページ全体のコンテンツが移動する可能性があります。
解決策は、size-adjust、ascent-override、descent-overrideプロパティを使用して、フォールバックフォントをカスタムフォントの寸法に合わせることです。これらは比較的新しいCSSフィーチャー(2024年現在、すべての最新ブラウザでサポート)で、フォールバックフォントを調整してカスタムフォントに合わせることができます。
例を示します:
@font-face {
font-family: 'BrandFont';
src: url('/fonts/brandfont.woff2') format('woff2');
font-display: swap;
}
@font-face {
font-family: 'BrandFont Fallback';
src: local('Arial');
size-adjust: 107%;
ascent-override: 95%;
descent-override: 25%;
}
.menu-link {
font-family: 'BrandFont', 'BrandFont Fallback', Arial, sans-serif;
}
size-adjustプロパティはフォールバックフォントをスケーリングして、x高さがカスタムフォントに合うようにします。ascent-overrideとdescent-overrideプロパティは垂直間隔を調整します。
適切な値を見つけるにはテストが必要です。Simon HearneによるFallback Font Generatorなどのツールはこのプロセスを自動化します。カスタムフォントを入力すると、ツールは一般的なシステムフォントの最適なオーバーライド値を計算します。
フォールバックフォントをこの方法でマッチングすると、フォント交換によるCLSはほぼゼロに減少します。テキストはまだフォールバックからカスタムフォントに交換されますが、寸法が同じなのでレイアウトは移動しません。
システムフォント:ゼロコストの代替案
最速のフォントはフォントがないこと、またはユーザーのデバイスに既にインストールされているシステムフォントです。システムフォントはダウンロードコストがゼロ、解析コストがゼロ、レイアウトシフトリスクがゼロです。
すべてのプラットフォームで見栄えの良い最新のシステムフォントスタック:
.menu-link {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', Arial, sans-serif;
}
これにより以下が得られます:
- macOSおよびiOS上のSan Francisco
- Windows上のSegoe UI
- Android上のRoboto
- Linux上のプラットフォーム固有のデフォルト
システムフォントはカスタムタイプフェイスほど独特ではありませんが、クリーンで読みやすく、プラットフォーム向けに最適化されています。多くのハイトラフィックサイト(GitHub、Medium、WordPress.com)はパフォーマンス上の理由でシステムフォントを使用しています。
ブランドガイドラインがカスタムフォントを要求する場合、ナビゲーションメニューではシステムフォントを使用し、見出し、ヒーロー テキスト、または本文コピーでカスタムフォントを使用することを検討してください。そこではメニューより視覚的に影響があります。メニューは機能的なUI です。見出しほどブランドを強く表現する必要はありません。
フォント読み込み時間を短縮するためのプリロード
font-display: swapでも、フォールバックが表示されてからカスタムフォントに交換されるまで遅延があります。遅い接続では500ミリ秒以上になる可能性があります。フォントファイルをプリロードすると、ブラウザはページ読み込みの早い段階で高い優先度で取得するよう指示され、交換遅延を短縮します。
<link rel="preload" href="/fonts/brandfont.woff2" as="font" type="font/woff2" crossorigin>
フォントが独自のドメインでホストされている場合でも、crossorigin属性が必要です。フォントはCORSモードで取得されるためです。
プリロードはFOUTを排除しませんが、期間を短縮します。メニューフォントが小さい(50KB未満)で、ブランドにとって重要な場合、プリロードは認識されるパフォーマンスを向上させることができます。
注意: プリロードはCSSやJavaScriptなどの他の重要なリソースと競合します。ページの上部で使用され、本当に重要なフォントのみをプリロードします。あまりにも多くのリソースをプリロードすると、初期レンダリングが遅くなる可能性があります。
アイコンフォント対インラインSVG
多くのナビゲーションメニューは、矢印、検索アイコン、ハンバーガーアイコンの場合、アイコンフォント(Font Awesome、Remix Icon、Material Icons)を使用します。アイコンフォントはフォントであるため、テキストフォントと同じ読み込み特性があります。デフォルトではFOIT、レイアウトシフトリスク、ダウンロードコスト(完全なアイコンフォントで通常50~150KB)です。
インラインSVGはメニューアイコンの方が良い選択肢です。インラインSVGはHTMLの一部であるため、ネットワークリクエストなし、フォント読み込み遅延なしで即座に表示されます。また、完全にスケーリングでき、CSSスタイリングをサポートします。
例:
<button class="menu-toggle" aria-label="Open menu">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="3" y1="12" x2="21" y2="12"></line>
<line x1="3" y1="6" x2="21" y2="6"></line>
<line x1="3" y1="18" x2="21" y2="18"></line>
</svg>
</button>
このハンバーガーアイコンは200バイトです。使用することのない2,000個のアイコンを持つ完全なアイコンフォントは150KBです。インラインSVGはFOIT問題も排除します—アイコンはHTMLの一部であるため即座に表示されます。
Navi+のような最新のメニューアプリはすべてのアイコンにインラインSVGを使用しており、これはアイコンフォント ベースのメニューが悩む多くのレイアウトシフト問題を回避する理由の1つです。
Shopify固有のフォント読み込み
Shopifyテーマは通常、3つの方法のいずれかでフォントを読み込みます。Google Fonts から、Shopify CDN から(テーマ設定フォントピッカーを介して)、またはテーマのassetsフォルダのカスタムフォントファイルから。
Google Fonts
テーマがGoogle Fontsを使用する場合、URLにdisplay=swapパラメータがあることを確認します。theme.liquidで次のような行を確認します:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600">
これを次のように変更します:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap">
Shopify CDNフォント
テーマがShopifyの組み込みフォントピッカー(設定 > タイポグラフィ)を使用する場合、Shopifyはそのプロセスから提供されたフォントを2023年以降は自動的にfont-display: swapを含めてCDNから提供します。何もする必要はありません。
カスタムフォントファイル
テーマのassetsフォルダにカスタムフォントファイルをアップロードした場合、CSSの@font-face宣言にfont-display: swapを追加します。
フォント読み込み影響を測定する
Chrome DevToolsを使用して、フォントがLCPとCLSにどのように影響するかを確認します。
FOITをチェック
DevToolsを開き、[ネットワーク]タブに移動し、「フォント」でフィルタして、ページを再度読み込みます。メニュー領域を見ます。メニューテキストが表示されるまでかなりの間、見えない場合、FOITがあります。font-display: swapを追加して修正します。
レイアウトシフトをチェック
DevToolsを開き、[パフォーマンス]タブに移動し、[記録]をクリック、ページを再度読み込み、記録を停止します。エクスペリエンスセクションで赤い「Layout Shift」バーを探します。1つをクリックして、どの要素が移動したかを確認します。メニューテキストがリストされている場合、フォント交換がレイアウトシフトを引き起こしました。フォールバックフォントマッチングを使用して修正します。
CLSを測定
Lighthouseテスト(DevToolsまたはPageSpeed Insights)を実行します。CLSスコアと「大きなレイアウトシフトを回避する」診断を見ます。フォントが原因としてリストされている場合、より良いフォールバックマッチングが必要、またはシステムフォントへの切り替えを検討する必要があります。
クイックウィンメニューがカスタムフォントを使用していてCLS問題を見ている場合、テストとしてシステムフォントスタックに切り替えてみてください。もう一度Lighthouseを実行します。CLSが大幅に低下した場合、カスタムフォントが問題でした。その後、カスタムフォントのブランド価値がパフォーマンスコストに値するかどうか、またはフォールバックマッチングを実装して両方を取得するかを決定できます。
良好なメニューフォント読み込みの外観
最適化されたナビゲーションメニューは、次の2つの方法のいずれかでフォントを処理します。
オプション1:システムフォント。 カスタムフォントなし、ダウンロードコストがゼロ、FOITがゼロ、レイアウトシフトがゼロ。メニューはネイティブ風のテキストで即座に表示されます。
.menu-link {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif;
}
オプション2:swapとフォールバックマッチングを備えたカスタムフォント。 メニューテキストはシステムフォントで即座に表示され、その後レイアウトシフトなしでカスタムフォントに交換されます。
@font-face {
font-family: 'BrandFont';
src: url('/fonts/brandfont.woff2') format('woff2');
font-display: swap;
}
@font-face {
font-family: 'BrandFont Fallback';
src: local('Arial');
size-adjust: 107%;
}
.menu-link {
font-family: 'BrandFont', 'BrandFont Fallback', Arial, sans-serif;
}
どちらのアプローチも、ページ読み込みの最初の1秒以内に読み取り可能なメニューをもたらします。これはLCPが測定するものです。最初のアプローチはシンプルで高速です。2番目のアプローチはわずかなパフォーマンスコストでブランド一貫性を保持します。
アイコンの場合、アイコンフォントの代わりにインラインSVGを使用します。アイコンは即座に表示され、完全にスケーリング可能で、150KBの代わりに数百バイトのコストがかかります。
デフォルトのフォント読み込み(FOIT、フォールバックマッチングなし)からこれらのパターンの1つに切り替えるほとんどのストアは、CLSが0.05~0.15ポイント低下し、LCPがモバイルで200~400ミリ秒改善するのを見ます。メニューはユーザーには同じに見えますが、ブラウザはそれをより高速かつスムーズにレンダリングします。
この記事は、より大きなガイドの一部です。Menu and LCP: how navigation blocks your largest contentful paintをご覧ください。