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

Core Web Vitals 向けにウェブフォントを最適化する。

このドキュメントでは、フォントに関するパフォーマンスのベスト プラクティスについて説明します。ウェブフォントがパフォーマンスに与える影響はさまざまです。

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

このドキュメントは、フォント読み込みフォント配信フォント レンダリングの 3 つのセクションで構成されています。各セクションでは、フォント ライフサイクルの特定の側面の仕組みと、それに応じたベスト プラクティスについて説明します。

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

ページのフォントが適切なタイミングでリクエストされているかどうか不明な場合は、Chrome DevTools の [ネットワーク] パネルにある [タイミング] タブで詳細を確認します。

DevTools の [Timing] タブ。

@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"
}

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

したがって、フォントの最適化を考える場合は、フォント ファイル自体と同じくらいスタイルシートを重視することが重要です。スタイルシートの内容や配信を変更すると、フォントが届くタイミングに大きな影響を与える可能性があります。同様に、使用されていない 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 宣言を無視します。慎重に使用する場合、単一のフォント形式の読み込みにのみ使用する必要があります。

ただし、外部スタイルシートを使用する場合は、最も重要なフォントをプリロードすると非常に効果的です。ブラウザは、フォントの必要性を後で検出するからです。

フォント配信

フォント配信が速くなると、テキストのレンダリングも速くなります。また、フォントが十分に早く配信されると、フォント スワップによるレイアウトのずれを回避できます。

セルフホスト フォントを使用する

理論上、自己ホスト型フォントを使用すると、サードパーティの接続設定が不要になるため、パフォーマンスが向上します。実際には、この 2 つのオプションのパフォーマンスの差は明確ではありません。たとえば、ウェブ アルマナックによると、サードパーティのフォントを使用しているサイトは、ファーストパーティのフォントを使用しているサイトよりもレンダリングが速いことが判明しています。

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

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

WOFF2 を使用する

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

ブラウザのサポート状況を踏まえ、専門家は WOFF2 のみを使用することを推奨しています。

実際、WOFF2 のみを使用して、他のものはすべて忘れる時期が来ていると考えます。

これにより、CSS とワークフローが大幅に簡素化され、フォントが誤って重複してダウンロードされたり、間違ってダウンロードされたりするのを防ぐことができます。WOFF2 がすべてのデバイスでサポートされるようになりました。そのため、古いブラウザをサポートする必要がある場合を除き、WOFF2 を使用してください。対応できない場合は、古いブラウザにはウェブフォントを配信しないことを検討してください。堅牢なフォールバック戦略を用意していれば、これは問題になりません。古いブラウザを使用しているユーザーには、代替フォントが表示されます。

Bram Stein、2022 年ウェブ アルマナック

フォントのサブセット

通常、フォント ファイルには、サポートされているさまざまな文字のグリフが多数含まれています。ただし、ページ上のすべての文字が必要ない場合は、フォントをサブセット化することでフォント ファイルのサイズを削減できます。

@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 範囲に一致する文字が 1 つ以上含まれている場合、フォント ファイルがダウンロードされます。unicode-range は、ページ コンテンツで使用されている言語に応じて異なるフォント ファイルを提供する場合によく使用されます。

unicode-range は、サブセット化の手法と組み合わせて使用されることがよくあります。サブセット フォントには、元のフォント ファイルに含まれていたグリフの一部が含まれています。たとえば、サイトでは、すべてのユーザーにすべての文字を提供するのではなく、ラテン文字とキリル文字に別々のサブセット フォントを生成します。

フォントあたりのグリフの数は大きく異なります。

  • ラテン文字フォントは通常、フォントあたり 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 パラメータを指定することでこれをサポートしています)を使用して、またはフォント ファイルを手動で編集してセルフホストすることで、フォントを手動でサブセット化できます。フォント サブセットを生成するツールには、subfontglyphanger があります。

フォント ライセンスを確認して、サブセット化とセルフホストを許可していることを常に確認してください。

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

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

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

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

font-family: system-ui

可変フォントの考え方は、複数のフォント ファイルの代わりに単一の可変フォントを使用できることです。可変フォントは、「デフォルト」のフォント スタイルを定義し、フォントを操作するための「軸」を指定することで機能します。たとえば、Weight 軸を持つ可変フォントを使用すると、従来はライト、レギュラー、太字、極太のフォントが別々に必要だった文字列を実装できます。

可変フォントに切り替えることでメリットが得られるユーザーは限られます。可変フォントには多くのスタイルが含まれているため、通常、1 つのスタイルのみを含む個別の可変フォントよりもファイルサイズが大きくなります。可変フォントを使用すると最も効果が期待できるのは、さまざまなフォント スタイルや太さを使用している(使用する必要のある)サイトです。

フォント レンダリング

まだ読み込まれていないウェブフォントの場合、ブラウザはジレンマに直面します。ウェブフォントが届くまでテキストのレンダリングを保留すべきか、それとも、ウェブフォントが届くまでフォールバック フォントでテキストをレンダリングするべきでしょうか?

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

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

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

font-display は、関連するウェブフォントが読み込まれていない場合に、テキストのレンダリングをどのように進めるかをブラウザに通知します。これは font-face ごとに定義されます。

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

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

ブロック期間 スワップ期間
自動 ブラウザによって異なる ブラウザによって異なる
ブロック 2 ~ 3 秒 無限
スワップ 0ms 無限
フォールバック 100ms 3 秒
省略可 100ms なし
  • ブロック期間: ブロック期間は、ブラウザがウェブフォント リクエストを送信したときに開始されます。ブロック期間中、ウェブフォントが使用できない場合、フォントは不可視のフォールバック フォントでレンダリングされるため、ユーザーにはテキストが見えなくなります。ブロック期間の終了時にフォントが使用できない場合は、代替フォントでレンダリングされます。
  • スワップ期間: スワップ期間はブロック期間の後に続きます。スワップ期間中にウェブフォントが利用可能になると、そのフォントが「スワップ」されます。

font-display 戦略は、パフォーマンスと美しさのトレードオフに関するさまざまな視点を表しています。そのため、アプローチをおすすめすることは困難です。これは、個々の好み、ウェブフォントがページやブランドにとってどの程度重要か、遅れて到着したフォントが入れ替わったときにどれほど違和感があるかによって異なります。

ほとんどのサイトでは、最優先事項に基づいて、次の 3 つの戦略が最も適しています。

  • パフォーマンス: font-display: optional を使用します。これは最も「パフォーマンスの高い」アプローチです。テキストのレンダリングは 100 ミリ秒以内に遅延され、フォント スワップに関連するレイアウトのずれがないことを確認できます。ただし、Web フォントが遅れて届いた場合は使用されません。

  • テキストをすばやく表示し、ウェブフォントも使用する: font-display: swap を使用しますが、レイアウトのずれを生じないように、フォントは十分に早い段階で配信してください。このオプションの欠点は、フォントが遅れて届いたときに、文字が急激に変化することです。

  • テキストが Web フォントで表示される: font-display: block を使用しますが、テキストの遅延を最小限に抑えるように、フォントを十分に早く配信してください。最初のテキストの表示が遅れる。この遅延にもかかわらず、テキストが実際には見えないように描画されるため、フォールバック フォント スペースがスペースの予約に使用され、レイアウトがずれる可能性があります。ウェブフォントが読み込まれると、差分スペースが必要になるため、ずれが生じることがあります。テキスト自体が移動しているようには見えないため、font-display: swap よりも違和感のない変化になる可能性があります。

また、これらの 2 つのアプローチを組み合わせることもできます。たとえば、ブランディングや視覚的に際立つページ要素には font-display: swap を使用します。本文のテキストに使用するフォントには font-display: optional を使用します。

アイコン フォント

従来のウェブフォントで効果的な font-display 戦略は、アイコンフォントでは効果的ではありません。通常、アイコン フォントの代替フォントはアイコン フォントとは大きく異なり、文字がまったく異なる意味を表す場合があります。そのため、アイコンフォントを使用すると、レイアウトが大幅にずれる可能性があります。

また、代替フォントを使用することは現実的ではない場合があります。可能であれば、アイコン フォントを SVG に置き換えます。これはユーザー補助にも適しています。一般的なアイコンフォントの新しいバージョンは、通常 SVG をサポートしています。SVG への切り替えについて詳しくは、Font Awesomeマテリアル アイコンをご覧ください。

代替フォントとウェブフォント間のずれを減らす

CLS の影響を軽減するには、size-adjust 属性を使用します。

まとめ

ウェブフォントは引き続きパフォーマンスのボトルネックですが、このボトルネックを可能な限り減らすために、ウェブフォントを最適化できるオプションはますます増えています。