ウェブのフォントサイズを縮小する

タイポグラフィは、優れたデザイン、ブランディング、読みやすさ、ユーザー補助機能において非常に重要です。ウェブフォントを使うと、これらのすべてに加えて、テキストの選択、検索、ズームが可能で、高 DPI に対応します。その結果、画面のサイズや解像度にかかわらず一貫性のある鮮明な良いテキスト レンダリングが実現されます。優れたデザイン、ユーザー エクスペリエンス、パフォーマンスを実現するにはウェブフォントが重要です。

ウェブフォントの最適化は全体的なパフォーマンス戦略における重要な要素です。フォントはそれぞれ追加のリソースです。フォントによってはテキストのレンダリングがブロックされることがありますが、ページでウェブフォントを使用しているからといってレンダリングが遅くなるわけではありません。逆に、最適化されたフォントを使い、それらをページ上でどのように読み込んで適用するのかを十分に検討することで、全体のページ サイズを削減してページのレンダリング時間を短縮することができます。

ウェブフォントの構造

ウェブフォントはグリフの集合であり、それぞれのグリフは文字または記号を表現するベクター図形です。そのため、特定のフォント ファイルのサイズは 2 つの単純な変数によって決まります。各グリフのベクターパスの複雑さと、特定のフォントにおけるグリフの数です。たとえば、ごく一般的なウェブフォントの 1 つである Open Sans には、ラテン文字、ギリシャ文字、キリル文字などの 897 個のグリフが含まれています。

フォント グリフ テーブル

フォントを選択する際は、どの文字セットがサポートされているのかを考慮することが重要です。ページ コンテンツを複数の言語にローカライズする必要がある場合は、一貫性のある外観やエクスペリエンスをユーザーに提供できるフォントを使用してください。たとえば、Google の Noto フォント ファミリーは世界中のすべての言語をサポートすることを目的としています。ただし、すべての言語を含む Noto の合計サイズは、ダウンロード用の ZIP ファイルでも 1.1GB を超えます。

この記事では、ウェブフォントのデリバリー ファイルサイズを削減する方法について説明します。

ウェブフォント フォーマット

現在ウェブでは、次の 2 種類のフォント コンテナ形式が推奨されています。

WOFFWOFF 2.0 は幅広くサポートされており、すべての最新ブラウザでサポートされています。

  • 最新のブラウザには WOFF 2.0 バリアントを提供します。
  • どうしても必要な場合(Internet Explorer 11 をサポートする必要がある場合など)は、WOFF をフォールバックとして提供します。
  • または、以前のブラウザではウェブフォントを使用しないで、システム フォントにフォールバックすることを検討してください。古いデバイスや制約の多いデバイスでも、パフォーマンスが向上する可能性があります。
  • WOFF と WOFF 2.0 は、現在使用されている最新のブラウザと以前のブラウザのすべてのベースをカバーしているため、EOT と TTF を使用する必要はありません。使用すると、ウェブフォント ダウンロード時間が長くなる可能性があります。

ウェブフォントと圧縮

WOFF と WOFF 2.0 の両方に圧縮機能が組み込まれています。WOFF 2.0 の内部圧縮では Brotli が使用され、WOFF よりも最大 30% 圧縮率が向上します。詳細については、WOFF 2.0 評価レポートをご覧ください。

なお、一部のフォント形式にはフォント ヒンティングカーニング情報など、プラットフォームによっては不要な追加のメタデータが含まれています。このため、ファイルサイズをさらに最適化可能です。たとえば、Google Fonts の場合、フォントごとに 30 を超える最適化された派生フォントが含まれており、それぞれのプラットフォームやブラウザに最適な派生フォントを自動的に検出して提供します。

@font-face を使用してフォント ファミリーを定義する

CSS @ ルールの @font-face を使うと、特定のフォント リソースについて、その場所、スタイル特性、使用すべき Unicode コードポイントを定義できます。こうした @font-face 宣言を組み合わせて使うことで「フォント ファミリー」を構築できます。ブラウザはこの「フォント ファミリー」を使用して、どのフォント リソースをダウンロードして現在のページに適用する必要があるかを判断します。

可変フォントを使用する

可変フォントを使用すると、フォントの複数のバリエーションが必要な場合に、フォントのファイルサイズを大幅に削減できます。通常のスタイルと太字のスタイルとその斜体バージョンを読み込む代わりに、すべての情報が含まれる 1 つのファイルを読み込むことができます。ただし、可変フォント ファイルのサイズは、個々のフォント バリエーションよりも大きくなりますが、多くのバリエーションの組み合わせよりも小さくなります。1 つの大きな可変フォントではなく、重要なフォント バリエーションを最初に提供し、他のバリエーションを後でダウンロードすることをおすすめします。

可変フォントは、すべてのモダン ブラウザでサポートされています。詳しくは、ウェブ上で指定可能なフォントについてをご覧ください。

適切な形式を選択する

それぞれの @font-face 宣言ではフォント ファミリーの名前を指定します。これは、複数の宣言の論理的なグループである [フォント プロパティ](スタイル、ウェイト、ストレッチ)として機能します。また、フォント リソースの場所の優先順位付きリストを指定する [src ディスクリプタ] も指定します。

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome.woff2') format('woff2'),
       /* Only serve WOFF if necessary. Otherwise,
          WOFF 2.0 is fine by itself. */
       url('/fonts/awesome.woff') format('woff');
}

@font-face {
  font-family: 'Awesome Font';
  font-style: italic;
  font-weight: 400;
  src: local('Awesome Font Italic'),
       url('/fonts/awesome-i.woff2') format('woff2'),
       url('/fonts/awesome-i.woff') format('woff');
}

まず、上記の例では Awesome Font という単一のファミリーを定義しています。このファミリーには 2 つのスタイル(normal と italic)があり、それぞれ異なるフォント リソース セットを指しています。さらに、それぞれの src ディスクリプタには、カンマで区切られた派生リソースの優先順位付きリストが含まれています。

  • local() ディレクティブを使用すると、ローカルにインストールされているフォントを参照、読み込み、使用できます。ユーザーのシステムにフォントがすでにインストールされている場合は、ネットワークを完全にバイパスするため、最も高速な方法です。
  • url() ディレクティブを使うと、外部フォントの読み込みができます。また、オプションの format() ヒントを含めて、指定した URL によって参照されるフォントの形式を指定できます。

ブラウザは、フォントが必要であると判断すると、指定されたリソースリストを指定された順序で調べ、該当するリソースの読み込みを試みます。たとえば前の例では次のようになります。

  1. ブラウザは、ページのレイアウトを行い、指定されたテキストをページに表示するためにどの派生フォントが必要なのかを判断します。ページの CSS オブジェクト モデル(CSSOM)に含まれないフォントは、不要であるためブラウザによってダウンロードされません。
  2. 必要なフォントごとに、ブラウザはローカルでフォントが使用可能かどうかを確認します。
  3. ローカルのフォントが使用できない場合は、ブラウザは外部定義を順番に調べます。
    • 形式ヒントが存在する場合、ブラウザは自身がサポートしているかどうかを調べ、サポートしている場合はダウンロードを開始します。そのヒントをサポートしていない場合は、次の形式ヒントを調べます。
    • 形式ヒントが存在しない場合、ブラウザはリソースをダウンロードします。

ローカル / 外部ディレクティブと適切な形式ヒントを組み合わせて使うことで、使用可能なすべてのフォント形式を指定して、残りの処理をブラウザに任せることができます。ブラウザは、どのリソースが必要なのかを判断して、最適な形式を自動的に選択します。

Unicode-range サブセット化

スタイル、ウェイト、ストレッチなどのフォント プロパティに加えて、@font-face ルールではそれぞれのリソースでサポートされる Unicode コードポイントのセットを定義することもできます。これにより、大きい Unicode フォントをより小さいサブセット(ラテン、キリル、ギリシャの各文字のサブセットなど)に分割し、特定のページでテキストをレンダリングするために必要なグリフだけをダウンロードできます。

unicode-range ディスクリプタを使うと、カンマで区切られた範囲値のリストを指定できます。範囲値はそれぞれ次の 3 つのうちいずれかの形式で指定できます。

  • 1 つのコードポイント(例: U+416
  • 範囲(例: U+400-4ff): 範囲のコードポイントの始めと終わりを指定
  • ワイルドカード範囲(例: U+4??): ? 文字は任意の 16 進数を表す

たとえば、Awesome Font ファミリーをラテン語と日本語のサブセットに分割し、ブラウザがそれぞれのサブセットを必要に応じてダウンロードするようにできます。

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-l.woff2') format('woff2');
  /* Latin glyphs */
  unicode-range: U+000-5FF;
}

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-jp.woff2') format('woff2');
  /* Japanese glyphs */
  unicode-range: U+3000-9FFF, U+ff??;
}

unicode-range によるサブセットを使い、スタイル別の派生フォントにそれぞれ別々のファイルを使うことで、より高速かつ効率よくダウンロードされる複合フォント ファミリーを定義できます。必要な派生フォントやサブセットをダウンロードするだけで済み、ページ上で表示されたり使用されたりすることが決してないサブセットをダウンロードする必要がなくなります。

ほとんどのブラウザは unicode-range をサポートしています。古いブラウザとの互換性を維持するには、「手動サブセット化」にフォールバックする必要があります。この場合は、必要なサブセットをすべて含んだ単一のフォント リソースを提供して、残りをブラウザから隠す必要があります。たとえば、ページでラテン文字しか使われていない場合は、それ以外のグリフを取り除いて、特定のサブセットを単独のリソースとして利用することができます。

  1. 必要なサブセットを決定する:
    • unicode-range によるサブセット化がブラウザでサポートされている場合は、自動的に適切なサブセットが選択されます。ページでは、サブセット ファイルを提供し、該当する unicode-range を @font-face ルールで指定するだけで済みます。
    • ブラウザで unicode-range によるサブセット化がサポートされていない場合は、ページで不要なサブセットをすべて隠す必要があります。つまり、デベロッパーが必要なサブセットを指定する必要があります。
  2. フォントのサブセットを生成する:
    • オープンソースの pyftsubset ツールを使ってフォントのサブセット化と最適化を行います。
    • Google フォントなどの一部のフォント サーバーは、デフォルトで自動的にサブセット化されます。
    • フォント サービスによってはカスタム クエリ パラメータによる手動サブセット化が可能です。この方法を使ってページで必要なサブセットを手動で指定できます。詳しくはフォント提供者のマニュアルをご覧ください。

フォントの選択と合成

フォント ファミリーは、複数のスタイル バリアント(標準、太字、斜体)と、スタイルごとの複数のウェイトで構成される場合があります。それぞれが、大きく異なるグリフ形状を含むことがあり、文字間隔やサイズ、さらには形状が完全に異なる場合があります。

フォントの太さ

上の図は、3 つの異なる太字ウェイトを提供するフォント ファミリーを表しています。

  • 400(通常)。
  • 700(太字)。
  • 900(極太)。

それ以外のウェイトの派生フォント(グレーで表示)はすべて、ブラウザによって最も近い派生フォントに自動的にマッピングされます。

指定されたウェイトに対応するフェイスが存在しない場合は、それに近いウェイトのフェイスが使用されます。一般に、太字のウェイトは、より重いウェイトのフェイスにマッピングされ、細字のウェイトは、より軽いウェイトのフェイスにマッピングされます。

CSS フォント マッチング アルゴリズム

斜体の派生フォントにも同様のロジックが適用されます。フォント デザイナーはどの派生フォントを生成するのかをコントロールし、ユーザーはどの派生フォントをページ上で使用するのかをコントロールします。派生フォントはそれぞれ別々のダウンロードになるため、派生フォントの数は少なく保つことをおすすめします。たとえば、Awesome Font ファミリー用に 2 つの太字のバリアントを定義できます。

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 400;
  src: local('Awesome Font'),
       url('/fonts/awesome-l.woff2') format('woff2');
  /* Latin glyphs */
  unicode-range: U+000-5FF;
}

@font-face {
  font-family: 'Awesome Font';
  font-style: normal;
  font-weight: 700;
  src: local('Awesome Font'),
       url('/fonts/awesome-l-700.woff2') format('woff2');
  /* Latin glyphs */
  unicode-range: U+000-5FF;
}

上の例で宣言した Awesome Font ファミリーは 2 つのリソースで構成されています。これらは同じラテン グリフ セット(U+000-5FF)を対象としていますが、標準(400)と太字(700)の 2 つの異なる「ウェイト」を提供します。しかし、いずれかの CSS ルールで、異なるフォント ウェイトを指定したり、font-style プロパティを italic に設定したりした場合はどうなりますか。

  • 正確に一致するフォントが見つからない場合、ブラウザは最も近いものを代用します。
  • スタイル別に一致するフォントが見つからない場合(上の例で斜体の派生フォントを宣言しなかった場合など)、ブラウザは独自の派生フォントを合成します。
フォント合成

上記の例では、Open Sans における実際のフォントと合成フォントの違いを示しています。合成の派生フォントはすべて、1 つの 400 ウェイトのフォントから生成されます。ご覧のように、著しい違いが見られます。太字とオブリークの派生フォントを生成する方法の詳細は指定されていません。したがって、その結果はブラウザごとに異なり、またフォントに大きく依存します。

ウェブフォントのサイズの最適化チェックリスト

  • フォントの利用を調査し監視する: ページ上でフォントを過度に使用しないようにし、フォントごとに使用するバリアントの数を最小限に抑えます。こうすることで、ユーザー エクスペリエンスの一貫性が高まり、動作が高速になります。
  • 可能であれば以前の形式は使用しないでください: EOT、TTF、WOFF 形式は WOFF 2.0 よりもサイズが大きいため、EOT と TTF は厳密には不要な形式ですが、Internet Explorer 11 をサポートする必要がある場合は WOFF を使用できます。最新のブラウザのみをターゲットとしている場合は、WOFF 2.0 のみを使用するのが最も簡単でパフォーマンスの高いオプションです。
  • フォント リソースをサブセット化する: 多数のフォントをサブセット化したり、複数の unicode-range に分割したりすることで、特定のページで必要なグリフだけを提供できます。その結果、ファイルサイズが減少し、リソースのダウンロード速度が速くなります。ただし、サブセットを定義する際はフォントの再利用を考慮して注意深く最適化してください。たとえば、ページごとに異なる文字セットをダウンロードする際、文字セットに重複が生じないようにします。スクリプト(ラテン文字やキリル文字など)に基づいてサブセット化することをおすすめします。
  • src リストで local() に優先順位を与える: src リストの最初に local('Font Name') をリストすることで、すでにインストールされているフォントに対して HTTP リクエストが行われないようにすることができます。
  • Lighthouse を使用してテキスト圧縮をテストします。

Largest Contentful Paint(LCP)と Cumulative Layout Shift(CLS)への影響

ページのコンテンツによっては、テキストノードが Largest Contentful Paint(LCP)の候補と見なされる場合があります。そのため、ユーザーがページのテキストをできるだけ早く見ることができるように、この記事のアドバイスに沿ってウェブフォントはできるだけ小さくすることが重要です。

最適化を行ったにもかかわらず、ウェブフォント リソースが大きいためにページのテキストが表示されるまでに時間がかかるのではないかと懸念している場合は、font-display プロパティにいくつかの設定があり、フォントがダウンロードされている間、テキストが表示されないようにするのに役立つことをご存じでしょうか。ただし、swap 値を使用すると、レイアウト シフトが大幅に発生し、サイトのCumulative Layout Shift(CLS)に影響する可能性があります。可能であれば、optional または fallback の値の使用を検討してください。

ウェブフォントがブランドイメージ(およびユーザー エクスペリエンス)に不可欠な場合は、ブラウザがフォントのリクエストを先行して行えるように、フォントをあらかじめ読み込むことを検討してください。これにより、font-display: swap を使用している場合はスワップ期間、font-display を使用していない場合はブロック期間の両方を短縮できます。