フォントに関するおすすめの方法

Core Web Vitals に合わせてウェブフォントを最適化します。

この記事では、フォントのパフォーマンスに関するベスト プラクティスについて説明します。ウェブフォントはさまざまな形でパフォーマンスに影響します。

  • テキストの表示の遅延: ウェブフォントが読み込まれていない場合、ブラウザは通常、テキストの表示を遅らせます。多くの場合、これにより First Contentful Paint(FCP)が遅延します。これにより、状況によっては Largest Contentful Paint(LCP)が遅延することがあります。
  • レイアウト シフト: フォントを入れ替えるとレイアウト シフトが生じる可能性があり、Cumulative Layout Shift(CLS)に影響します。このようなレイアウト シフトは、ウェブフォントとその代替フォントがページ上の占有するスペースが異なる場合に生じます。

この記事は、フォントの読み込みフォントの配信フォントのレンダリングの 3 つのセクションで構成されています。各セクションでは、フォント ライフサイクルの特定の側面がどのように機能するかを説明し、対応するベスト プラクティスを提供します。

フォントを読み込んでいます

フォントは通常、重要なリソースです。フォントがないとユーザーはページ コンテンツを表示できない可能性があります。したがって、フォント読み込みに関するベスト プラクティスでは、できるだけ早い段階でフォントを読み込むことに重点を置くのが一般的です。サードパーティのサイトから読み込まれるフォントには特に注意が必要です。このようなフォント ファイルをダウンロードする際は、個別の接続設定が必要になるためです。

ページのフォントが時間内にリクエストされているかわからない場合は、Chrome DevTools の [ネットワーク] パネルにある [タイミング] タブで詳細をご確認ください。

DevTools の [タイミング] タブのスクリーンショット

@font-face について

フォント読み込みのベスト プラクティスを詳しく見ていく前に、@font-face の仕組みと、それがフォントの読み込みに与える影響を理解しておくことが重要です。

@font-face 宣言は、ウェブフォントを扱ううえで不可欠な部分です。少なくとも、フォントを参照するために使用する名前を宣言し、対応するフォント ファイルの場所を示します。

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
}

よくある誤解は、@font-face 宣言が発生したときにフォントがリクエストされるというものですが、これは真実ではありません。@font-face 宣言だけでは、フォントのダウンロードはトリガーされません。フォントは、ページで使用されているスタイルで参照されている場合にのみダウンロードされます。たとえば、次のようにします。

@font-face {
  font-family: "Open Sans";
  src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
}

h1 {
  font-family: "Open Sans"
}

つまり、上記の例では、ページに <h1> 要素が含まれている場合のみ、Open Sans がダウンロードされます。

そのため、フォントの最適化を検討する際には、フォント ファイル自体と同様にスタイルシートについても考慮することが重要です。スタイルシートのコンテンツまたは配信方法を変更すると、フォントが到着するタイミングに大きな影響を与える可能性があります。同様に、使用していない CSS を削除し、スタイルシートを分割すると、ページで読み込まれるフォントの数を減らすことができます。

インライン フォント宣言

ほとんどのサイトでは、フォント宣言やその他の重要なスタイル設定を外部スタイルシートに含めるよりも、メイン ドキュメントの <head> でインライン化する方が大きなメリットが得られます。これにより、外部スタイルシートがダウンロードされるのを待たずにブラウザがフォント宣言をすぐに検出できるようになります。

<head>
  <style>
    @font-face {
        font-family: "Open Sans";
        src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
    }

    body {
        font-family: "Open Sans";
    }

    ...etc.

  </style>
</head>

クリティカル CSS のインライン化は、すべてのサイトで実現できるわけではない、より高度な手法である可能性があります。パフォーマンス上のメリットは明らかですが、必然的に CSS(理想的には重要な CSS)が適切にインライン化され、追加の CSS がレンダリング ブロックなしで配信されるように、追加のプロセスとビルドツールが必要になります。

重要なサードパーティの送信元に事前に接続する

サイトでサードパーティのサイトからフォントを読み込む場合は、preconnect リソースヒントを使用して、サードパーティのオリジンとの早期接続を確立することを強くおすすめします。リソースヒントはドキュメントの <head> に配置する必要があります。以下のリソースヒントは、フォント スタイルシートを読み込むための接続を設定します。

<head>
  <link rel="preconnect" href="https://fonts.com">
</head>

フォント ファイルのダウンロードに使用する接続を事前に接続するには、crossorigin 属性を使用する別の preconnect リソースヒントを追加します。スタイルシートとは異なり、フォント ファイルは CORS 接続を介して送信する必要があります。

<head>
  <link rel="preconnect" href="https://fonts.com">
  <link rel="preconnect" href="https://fonts.com" crossorigin>
</head>

preconnect リソースヒントを使用する場合は、フォント プロバイダが別のオリジンのスタイルシートとフォントを提供する可能性があることに留意してください。たとえば、Google Fonts では preconnect リソースヒントは次のように使用されます。

<head>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
</head>

preload を使用してフォントを読み込む場合は注意してください

preload は、ページ読み込みプロセスの早い段階でフォントを検出可能にするのに非常に効果的ですが、ブラウザのリソースを他のリソースの読み込みから解放するという代償を伴います。

フォント宣言をインライン化し、スタイルシートを調整するほうが効果的な場合があります。これらの調整により、単に回避策を提供するだけでなく、発見されなくなったフォントの根本原因への対処に近づきます。

また、フォント読み込み戦略として preload を使用する場合も、ブラウザに組み込まれたコンテンツ ネゴシエーション戦略の一部が回避されるため、慎重に行う必要があります。たとえば、preloadunicode-range 宣言を無視します。慎重に使用する場合は、1 つのフォント形式を読み込むためにのみ使用してください。

ただし、外部のスタイルシートを使用する場合、最も重要なフォントをプリロードしておくことは非常に効果的です。これは、他の方法ではブラウザがフォントが必要かどうかを後で発見するためです。

フォントの配信

フォント配信の高速化により、テキストのレンダリングが高速化されます。また、フォントを早めに配信すれば、フォントの入れ替えによるレイアウト シフトを回避できます。

自己ホスト型フォントの使用

紙では、自己ホスト型フォントを使用すると、サードパーティの接続設定が不要なため、パフォーマンスが向上します。ただし、実際には、これら 2 つのオプションのパフォーマンスの違いはそれほど明確ではありません。たとえば、Web Almanac の調査によると、サードパーティのフォントを使用したサイトは、ファースト パーティのフォントを使用したフォントを使用したサイトよりもレンダリングが速いことがわかりました。

自己ホスト型フォントの使用を検討している場合は、サイトでコンテンツ配信ネットワーク(CDN)HTTP/2 を使用していることを確認してください。これらのテクノロジーを使用しないと、自己ホスト型フォントでパフォーマンスが向上する可能性は低くなります。詳細については、コンテンツ配信ネットワークをご覧ください。

自己ホスト型フォントを使用する場合は、サードパーティのフォント プロバイダが通常自動的に提供するフォント ファイルの最適化(フォントのサブセット化や WOFF2 圧縮など)も適用することをおすすめします。最適化を適用するために必要な作業量は、サイトでサポートされている言語によって若干異なります。特に、CJK 言語向けのフォントの最適化は特に困難です。

WOFF2 を使用する

最新のフォントの中でも、WOFF2 は最新のフォントで、ブラウザのサポートも広く、圧縮率も最も優れています。Brotli を使用しているため、WOFF2 は WOFF よりも 30% 圧縮効率が高く、ダウンロードするデータが少なくなるため、パフォーマンスが向上します。

ブラウザのサポートを考慮すると、エキスパートは現在、WOFF2 のみを使用することを推奨しています。

むしろ、「WOFF2 のみを使用し、それ以外は何もしない」と宣言する時期でもあると考えています。

これにより、CSS とワークフローが大幅に簡素化され、フォントが誤って二重にダウンロードされたり、誤ってダウンロードされたりするのを防ぐことができます。WOFF2 がすべての国でサポートされるようになりました。そのため、かなり古いブラウザをサポートする必要がない限り、WOFF2 を使用してください。使用できない場合は、そうした古いブラウザにはウェブフォントを一切提供しないことを検討します。堅牢なフォールバック戦略を策定しておけば、これは問題になりません。古いブラウザを使用しているユーザーには、代替フォントのみが表示されます。

Bram Stein、『2022 Web Almanac』より

サブセット フォント

通常、フォント ファイルには、サポートされるさまざまな文字のグリフが大量に含まれています。ただし、ページ上のすべての文字が必要なわけではないため、フォントのサブセット化を使用することでフォント ファイルのサイズを小さくすることができます。

@font-face 宣言の unicode-range 記述子は、フォントに使用できる文字をブラウザに通知します。

@font-face {
    font-family: "Open Sans";
    src: url("/fonts/OpenSans-Regular-webfont.woff2") format("woff2");
    unicode-range: U+0025-00FF;
}

Unicode 範囲に一致する文字がページに含まれている場合、フォント ファイルがダウンロードされます。unicode-range は通常、ページ コンテンツで使用されている言語に応じて異なるフォント ファイルを表示するために使用されます。

unicode-range は多くの場合、サブセット化手法と組み合わせて使用されます。サブセット フォントには、元のフォント ファイルに含まれていたグリフのごく一部が含まれます。たとえば、すべてのユーザーにすべての文字を表示するのではなく、ラテン文字とキリル文字用に別々のサブセット フォントを生成するサイトでは、1 フォントあたりのグリフ数は大きく異なります。ラテン系フォントでは通常、1 フォントあたり 100 ~ 1,000 グリフになりますが、CJK フォントでは 10,000 文字を超える場合があります。未使用のグリフを削除すると、フォントのファイルサイズを大幅に縮小できます。

フォント プロバイダによっては、異なるバージョンのフォント ファイルとサブセットを自動的に提供する場合があります。たとえば、Google Fonts では、デフォルトでこのように設定されています。

/* devanagari */
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJbecnFHGPezSQ.woff2) format('woff2');
  unicode-range: U+0900-097F, U+1CD0-1CF6, U+1CF8-1CF9, U+200C-200D, U+20A8, U+20B9, U+25CC, U+A830-A839, U+A8E0-A8FB;
}
/* latin-ext */
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJnecnFHGPezSQ.woff2) format('woff2');
  unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://fonts.gstatic.com/s/poppins/v20/pxiEyp8kv8JHgFVrJJfecnFHGPc.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

自己ホスティングに移行する場合、この最適化は見落とされがちで、ローカルのフォント ファイルが大きくなる可能性があります。

フォント プロバイダが許可している場合は、API(Google Fonts では text パラメータを指定)を使用するか、フォント ファイルを手動で編集してから自己ホストすることで、フォントを手動でサブセット化することもできます。フォント サブセットを生成するためのツールには、サブフォントグリファンガーなどがあります。ただし、使用しているフォントのライセンスを確認して、サブセット化と自己ホスティングを許可していることをご確認ください

ウェブフォントの使用を減らす

配信が最も速いフォントとは、そもそもリクエストされていないフォントです。システム フォントと可変フォントの 2 つは、サイトで使用するウェブフォントの数を削減できる 2 つの方法です。

システム フォントは、ユーザーのデバイスのユーザー インターフェースで使用されるデフォルトのフォントです。システム フォントは通常、オペレーティング システムやバージョンによって異なります。フォントはすでにインストールされているため、ダウンロードする必要はありません。システム フォントは本文には特に適しています。

CSS でシステム フォントを使用するには、フォント ファミリーとして system-ui を指定します。

font-family: system-ui

可変フォントの背景にある考え方は、1 つの可変フォントで複数のフォント ファイルの代わりとして使用できることです。可変フォントでは、「デフォルト」のフォント スタイルを定義し、フォントを操作するための「軸」を指定します。たとえば、Weight 軸を持つ可変フォントを使用すると、以前はライト、レギュラー、太字、極太のフォントで別々のフォントを使用する必要があったレタリングを実装できます。

可変フォントに切り替えることで、すべてのユーザーにとってメリットがあるわけではありません。可変フォントには多くのスタイルが含まれているため、通常、スタイルが 1 つのみの可変フォント以外の個々のフォントよりもファイルサイズが大きくなります。可変フォントの使用による最大の改善が見られたサイトは、さまざまなフォント スタイルと太さを使用している(使用する必要があります)。

フォントのレンダリング

まだ読み込まれていないウェブフォントが表示されると、ブラウザは「そのウェブフォントが到着するまでテキストのレンダリングを保留すべきか」というジレンマに直面します。それとも、ウェブフォントが到着するまで代替フォントでテキストをレンダリングすべきでしょうか。

ブラウザによって、このシナリオの扱いは異なります。デフォルトでは、Chromium ベースと Firefox のブラウザでは、関連付けられたウェブフォントが読み込まれていない場合、テキストの表示が最大 3 秒間ブロックされます。Safari では、テキストの表示が無期限にブロックされます。

この動作は、font-display 属性を使用して構成できます。この選択は重大な影響を及ぼす可能性があります。font-display は、LCP、FCP、レイアウトの安定性に影響を与える可能性があります。

適切な font-display 戦略を選択する

font-display は、関連付けられたウェブフォントが読み込まれていない場合にテキスト レンダリングを進める方法をブラウザに通知します。フォント フェースごとに定義されます。

@font-face {
  font-family: Roboto, Sans-Serif
  src: url(/fonts/roboto.woff) format('woff'),
  font-display: swap;
}

font-display に指定できる値は次の 5 つです。

ブロック期間 スワップ期間
Auto ブラウザによって異なる ブラウザによって異なる
ブロック 2 ~ 3 秒 無限
入れ替える 0 ミリ秒 無限
フォールバック 100ms 3 秒
任意 100ms なし
  • ブロック期間: ブラウザがウェブフォントをリクエストすると、ブロック期間が開始されます。ブロック期間中、ウェブフォントが使用できない場合、フォントは非表示の代替フォントで表示されるため、テキストはユーザーに表示されません。ブロック期間の終了時にフォントを使用できない場合は、代替フォントで表示されます。
  • スワップ期間: スワップ期間はブロック期間の後です。スワップ期間中にウェブフォントが使用可能になると、スワップされます。

font-display 戦略は、パフォーマンスと美しさのトレードオフに関するさまざまな視点を反映しています。そのため、個人の好み、ページやブランドに対するウェブフォントの重要性、遅れて到着するフォントがスワップイン時にどれほど不快になるかによって、推奨されるアプローチを指定するのは困難です。

ほとんどのサイトでは、次の 3 つの戦略が最も適用できます。

  • パフォーマンスが最優先事項の場合: font-display: optional を使用します。これが最も「パフォーマンス」に優れたアプローチです。テキスト レンダリングの遅延が 100 ミリ秒以下で、フォントの入れ替えに関連するレイアウト シフトが発生しないことが保証されます。ただし、ここでの欠点は、到着が遅れるとウェブフォントが使用されないということです。

  • テキストをすばやく表示することが最優先事項であり、ウェブフォントが確実に使用されるようにするには: font-display: swap を使用します。ただし、レイアウト シフトが発生しないように、フォントを早めに配信してください。このオプションの欠点は、フォントが遅れて到着すると不快感を与えることです。

  • テキストがウェブフォントで表示されるようにすることが最優先事項である場合: font-display: block を使用しますが、テキストの遅延が最小限になるようにフォントを早めに配信してください。この方法の欠点は、最初のテキスト表示が遅れることです。このように表示されても、テキストは実際には表示されない状態で描画されるため、レイアウト シフトが発生する可能性があります。そのため、代替フォント スペースを使用してスペースが確保されます。ウェブフォントが読み込まれると、異なるスペースが必要になり、シフトが必要になる可能性があります。ただし、テキスト自体はシフトしていると認識されないため、font-display: swap よりも不快に感じることはありません。

また、この 2 つの方法を組み合わせることもできます。たとえば、ブランディングやその他の視覚的に特徴的なページ要素には font-display: swap を使用し、本文のテキストで使用するフォントには font-display: optional を使用します。

代替フォントとウェブフォントの差を減らす

CLS の影響を軽減するには、新しい size-adjust 属性を使用します。詳しくは、CSS size-adjust に関する記事をご覧ください。これは Google のツールセットに新たに追加されたものであり、より高度であり、現時点では少し手作業です。とにかくテストして、今後のツールの改良に期待できることは間違いありません。

まとめ

ウェブフォントは依然としてパフォーマンスのボトルネックですが、このボトルネックをできるだけ減らすためにウェブフォントを最適化できる選択肢は増え続けています。