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

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 ミリ秒以下であり、フォント スワップに関連するレイアウト シフトがないことが保証されます。この方法の短所は、到着が遅れるとウェブフォントが使用されないことです。

  • テキストをすばやく表示し、ウェブフォントを引き続き使用する: font-display: swap を使用しますが、レイアウト シフトの発生を避けるために、フォントを早めに配信する必要があります。このオプションの欠点は、フォントが遅れて届いたときに、文字が急激に変化することです。

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

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

アイコン フォント

従来のウェブフォントでは効果的な font-display 戦略が、アイコン フォントではうまく機能しません。通常、アイコン フォントの代替フォントはアイコン フォントとは大きく異なり、文字がまったく異なる意味を表す場合があります。その結果、アイコン フォントが原因でレイアウトが大きく変わる可能性が高くなります。

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

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

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

まとめ

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