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

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 をフォント読み込み戦略として使用する場合も、ブラウザの組み込みコンテンツ交渉戦略の一部をバイパスするため、慎重に使用する必要があります。たとえば、preload では unicode-range 宣言が無視されるため、慎重に使用する場合は、1 つのフォント形式を読み込む場合にのみ使用してください。

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

フォント配信

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

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

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

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

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

WOFF2 を使用する

最新のフォント形式の中で、WOFF2 は最も新しい形式で、最も広範なブラウザでサポートされており、圧縮率も最も優れています。Brotli を使用するため、WOFF2 は 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 でシステム フォントを使用するには、フォント ファミリーとして system-ui を指定します。

font-family: system-ui

可変フォントの背後にある考え方は、1 つの可変フォントを複数のフォント ファイルの代わりに使用できるということです。可変フォントは、「デフォルト」のフォントスタイルを定義し、フォントを操作するための「軸」を提供する仕組みで動作します。たとえば、Weight 軸を持つ可変フォントを使用すると、従来はライト、レギュラー、太字、極太の個別のフォントが必要だった文字を、1 つのフォントで実装できます。

可変フォントへの切り替えがすべてのユーザーにとって有益であるとは限りません。可変フォントには多くのスタイルが含まれているため、通常、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 を使用しますが、レイアウト シフトが発生しないように、フォントは十分に早いタイミングで配信してください。このオプションの欠点は、フォントが遅れて届いたときに、文字が急激に変化することです。

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

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

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

CLS への影響を軽減するには、新しい size-adjust 属性を使用できます。詳しくは、CSS size-adjust に関する記事をご覧ください。この機能はツールセットに非常に最近追加されたため、現在は高度で手動的な作業が若干必要です。ぜひ試していただき、今後のツールの改善にご期待ください。

まとめ

ウェブフォントは依然としてパフォーマンスのボトルネックですが、ウェブフォントを最適化して可能な限りこのボトルネックを軽減できる選択肢は広がり続けています。