ウェブフォントの最適化

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

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

ウェブフォントの仕組み

TL;DR

  • Unicode フォントには数千のグリフが含まれることがあります。
  • フォントには WOFF2、WOFF、EOT、TTF の 4 つの形式があります。
  • 一部のフォント形式では GZIP 圧縮を使う必要があります。

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

フォントのグリフ テーブル

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

ウェブでフォントを使用する際は、タイポグラフィによってパフォーマンスが低下しないように十分注意する必要があります。幸い、ウェブ プラットフォームには必要な基本要素がすべて用意されています。以降、このガイドでは、パフォーマンスを損なわずにウェブフォントを活用するための実践的な方法について説明します。

ウェブフォントの形式

現在ウェブでは、EOTTTFWOFFWOFF2 の 4 種類のフォント コンテナ形式が利用されています。幅広い選択肢があるにもかかわらず、残念ながら、新旧のすべてのブラウザで動作する単一の普遍的な形式はありません。EOT は IE のみです。TTF は IE では一部しかサポートされていません。WOFF は最も幅広くサポートされていますが、一部の旧式のブラウザでは利用できません。WOFF 2.0 のサポートについては、多数のブラウザで現在対応中です

ではどのように対処すればよいでしょうか。すべてのブラウザで動作する単一の形式はありません。これは、一貫性のあるエクスペリエンスを提供するためには、複数の形式を提供する必要があることを意味します。

  • WOFF 2.0 派生フォントをサポートしているブラウザには WOFF 2.0 を提供します。
  • 大部分のブラウザには WOFF 派生フォントを提供します。
  • 旧式の Android ブラウザ(4.4 より前)には TTF 派生フォントを提供します。
  • 旧式の IE ブラウザ(IE9 より前)には EOT を提供します。

注: 正確には、SVG フォント コンテナもありますが、IE や Firefox では一切サポートされておらず、Chrome では現在はサポートを終了しています。使用範囲が限られるため、このガイドでは説明しません。

圧縮を利用したフォントサイズの削減

フォントはグリフのコレクションであり、それぞれのグリフは文字の形状を表すパスのセットです。それぞれのグリフは異なりますが、GZIP や互換性のある圧縮ツールによって圧縮可能な類似情報が多数含まれています。

  • EOT 形式と TTF 形式はデフォルトで圧縮されません。これらの形式を提供する場合は GZIP 圧縮を適用するようにサーバーを設定します。
  • WOFF ではフォントデータが圧縮されます。ビルトインの WOFF 圧縮ツールで最適な圧縮設定を使用していることを確認してください。
  • WOFF2 では独自の前処理アルゴリズムと圧縮アルゴリズムが使用されており、他の形式よりも約 30% ファイルサイズが縮小します。詳細については、WOFF 2.0 評価レポートをご覧ください。

なお、一部のフォント形式にはフォント ヒンティング情報カーニング情報など、プラットフォームによっては不要な追加のメタデータが含まれています。このため、ファイルサイズをさらに最適化可能です。使用可能な最適化オプションについては各フォント圧縮ツールのマニュアルをご覧ください。最適化を行う場合は、必ず適切なインフラストラクチャを配備して、最適化後のフォントをテストしたうえで、それらを各ブラウザに提供するようにしてください。たとえば、Google Fonts の場合、フォントごとに 30 を超える最適化された派生フォントが含まれており、それぞれのプラットフォームやブラウザに最適な派生フォントを自動的に検出して提供します。

注: EOT、TTF、WOFF 形式には Zopfli 圧縮の使用を検討してください。Zopfli は zlib と互換性のある圧縮ツールで、gzip と比べてファイルサイズが最大で 5% 削減されます。

@font-face を使用したフォント ファミリーの定義

TL;DR

  • 複数のフォント形式を指定するには、 format() ヒントを使用します。
  • 多数の Unicode フォントをサブセットにまとめることでパフォーマンスが向上します。unicode-range でサブセット化して、旧式のブラウザの場合は代わりに手動でサブセット化します。
  • スタイル別の派生フォントの数が減り、ページやテキスト表示のパフォーマンスが向上します。

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

形式の選択

それぞれの @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'), 
       url('/fonts/awesome.woff') format('woff'),
       url('/fonts/awesome.ttf') format('truetype'),
       url('/fonts/awesome.eot') format('embedded-opentype');
}

@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'),
       url('/fonts/awesome-i.ttf') format('truetype'),
       url('/fonts/awesome-i.eot') format('embedded-opentype');
}

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

  • local() ディレクティブを使うと、ローカルにインストールされているフォントを参照、読み込み、使用できます。
  • url() ディレクティブを使うと、外部フォントの読み込みができます。また、オプションの format() ヒントを含めて、指定した URL によって参照されるフォントの形式を指定できます。

注: いずれかのデフォルト システム フォントをコンテンツで参照している場合を除き、ユーザーがシステム フォントをローカルにインストールしていることは実際にはほとんどありません。特にモバイル端末では、追加のフォントを「インストール」することは実質的に不可能です。そのため、外部フォントの場所のリストを常に提供する必要があります。

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

  1. ブラウザは、ページのレイアウトを行い、指定されたテキストをページに表示するためにどの派生フォントが必要なのかを判断します。
  2. それぞれの必要なフォントについて、ブラウザは、ローカルのフォントが使用できるかどうかを調べます。
  3. ローカルのフォントが使用できない場合は、ブラウザは外部定義を順番に調べます。
    • 形式ヒントが存在する場合、ブラウザは自身がサポートしているかどうかを調べ、サポートしている場合はダウンロードを開始します。サポートしていない場合は次の形式ヒントを調べます。
    • 形式ヒントが存在しない場合、ブラウザはリソースをダウンロードします。

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

注: 派生フォントの指定順序は重要です。ブラウザは、サポートしている最初の形式を選択します。したがって、たとえば、新しいブラウザで WOFF2 を使いたい場合は、WOFF の前に WOFF2 宣言を記述します。

uniode-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'), 
       url('/fonts/awesome-l.woff') format('woff'),
       url('/fonts/awesome-l.ttf') format('truetype'),
       url('/fonts/awesome-l.eot') format('embedded-opentype');
  unicode-range: U+000-5FF; /* Latin glyphs */
}

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

注: unicode-range によるサブセット化は特にアジア系の言語で重要です。これらの言語では、グリフの数が西洋言語よりもずっと多く、通常の「フル装備の」フォントではそのサイズが数十キロバイト単位ではなく数メガバイト単位に及ぶことが多くあります。

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

ただし、unicode-range には 1 つだけ、すべてのブラウザがサポートしているわけではないという小さな欠点があります。 unicode-range ヒントを無視してすべての派生フォントをダウンロードするブラウザもあれば、@font-face 宣言をまったく処理できないブラウザもあります。

こうした問題に対処するには、旧式のブラウザで代わりに「手動サブセット化」を行う必要があります。

旧式のブラウザは必要なサブセットだけを選択できる機能を備えておらず、複合フォントを構築できないため、代わりに、必要なサブセットをすべて含んだ単一のフォント リソースを提供して、残りをブラウザから隠す必要があります。たとえば、ページでラテン文字しか使われていない場合は、それ以外のグリフを取り除いて、特定のサブセットを単独のリソースとして利用することができます。

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

フォントの選択と合成

フォント ファミリーはそれぞれ、複数のスタイル別の派生フォント(標準、太字、斜体)と、スタイルごとの複数のウェイトで構成されますが、さらにスタイルに含まれるグリフ形状がスタイルごとに大きく異なる場合があります。たとえば、スペーシングやサイジングが異なる場合や、形状が完全に異なる場合があります。

フォント ウェイト

たとえば上の図は、 400(標準)、700(太字)、900(極太)の 3 つの異なる太字ウェイトを提供するフォント ファミリーを表しています。それ以外のウェイトの派生フォント(グレーで表示)はすべて、ブラウザによって最も近い派生フォントに自動的にマッピングされます。

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

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

italic の派生フォントにも同様のロジックが適用されます。フォント デザイナーはどの派生フォントを生成するのかをコントロールし、ユーザーはどの派生フォントをページ上で使用するのかをコントロールします。

派生フォントはそれぞれ別々のダウンロードになるため、派生フォントの数は少なく保つことをおすすめします。 たとえば、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'), 
       url('/fonts/awesome-l.woff') format('woff'),
       url('/fonts/awesome-l.ttf') format('truetype'),
       url('/fonts/awesome-l.eot') format('embedded-opentype');
  unicode-range: U+000-5FF; /* Latin glyphs */
}

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

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

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

フォントの合成

作成者は、斜体にすると形状が大きく変わるキリル文字など、合成による方法が適さない場合があることにも注意する必要があります。いずれの場合も、合成バージョンに頼るよりも実際の斜体フォントを使用する方が良いと言えます。

CSS3 の font-style

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

注: 最適な一貫性と見栄えを保つには、合成フォントを使用しないようにします。代わりに、使用する派生フォントの数を最小限に抑えて、それらの場所を指定してください。そうすることで、ページ上で使用されているときにブラウザでフォントをダウンロードできます。ただし、場合によっては[合成の派生フォント]が使用可能な選択肢となることがあります。使用の際は注意してください。

読み込みと表示の最適化

TL;DR

  • フォント リクエストはレンダリング ツリーが構築されるまで遅延されるため、テキストのレンダリングが遅れることがあります。
  • Font Loading API を使うと、フォントの読み込みとレンダリング処理を独自実装して、デフォルトの遅延フォント読み込みをオーバーライドできます。
  • フォントをインライン化すると、旧式のブラウザでデフォルトの遅延フォント読み込みをオーバーライドできます。

「フル装備の」ウェブフォントには、場合によっては必要ないスタイル別派生フォントや、使用されないグリフもすべて含まれているため、ダウンロードのサイズがあっという間に数メガバイトに及んでしまいます。この問題に対処するため、@font-face CSS ルールではフォント ファミリーをリソースのコレクション(Unicode サブセット、個別のスタイル別派生フォントなど)に分割できるようになっています。

これらが宣言されている場合、ブラウザは必要なサブセットや派生フォントを判断して、テキストのレンダリングに最小限必要なセットをダウンロードします。この動作は非常に便利ですが、クリティカル レンダリング パスの中でパフォーマンスのボトルネックが生じたり、テキストのレンダリングが遅れたりするなど、回避すべき副作用が生じる可能性もあるので注意が必要です。

ウェブフォントとクリティカル レンダリング パス

フォントの遅延読み込みは、実はテキストのレンダリングが遅れるという重要な問題を引き起こす場合があります。ブラウザ側でテキストのレンダリングに必要なフォント リソースを判別するには、まず、DOM ツリーと CSSOM ツリーからレンダリング ツリーを構築する必要があります。その結果、フォントのリクエストが他の重要なリソースよりもずっと後になるため、リソースを取得するまでブラウザでのテキストのレンダリングがブロックされることがあります。

フォントのクリティカル レンダリング パス

  1. ブラウザが HTML ドキュメントをリクエストする。
  2. ブラウザが HTML レスポンスの解析と DOM の構築を始める。
  3. ブラウザが CSS、JS、その他のリソースを検出し、リクエストを発信する。 1.すべての CSS コンテンツを受信した時点で、ブラウザが CSSOM を構築し、DOM ツリーと結合して表示ツリーを構築する。
    • ページ上の指定されたテキストのレンダリングに必要な派生フォントがレンダリング ツリーによって示された時点で、フォント リクエストがディスパッチされる。
  4. ブラウザがレイアウトを実行し、コンテンツを画面に描画する。
    • フォントがまだ使用できない場合、ブラウザはいずれのテキスト ピクセルもレンダリングできない。
    • フォントが使用できるようになるとブラウザがテキスト ピクセルをペイントする。

ページ コンテンツの初回ペイント(レンダリング ツリー構築のすぐ後に実行可能)と、フォント リソースのリクエストとの間に起こる「競合」によって、ブラウザがページ レイアウトをレンダリングする一方で、すべてのテキストは省略する「空テキスト問題」が発生します。

実際の動作はブラウザによって次のように異なります。

  • Safari では、フォントのダウンロードが完了するまでテキストのレンダリングが保留されます。
  • Chrome と Firefox では、フォントの表示が最大 3 秒間保留されます。その後で代替フォントを使用し、フォントのダウンロードが完了すると、ダウンロードされたフォントを使用してもう一度テキストを再表示します。
  • IE では、リクエストされたフォントがまだ使用できない場合は代替フォントを使用して即座にレンダリングを行い、フォントのダウンロードが完了した時点でテキストの再レンダリングを行います。

こうしたさまざまな表示方法についてはそれぞれに賛否両論があります。再レンダリングを嫌う人もいれば、すぐに結果が表示されることを好み、フォントのダウンロードが完了した後でページがリフローされるのは気にならないという人もいます。ここではこの議論に立ち入りません。重要なのは、遅延読み込みではバイト数が減少する一方で、テキストのレンダリングが遅れる可能性もある、ということです。 次に、この動作を最適化する方法について見てみましょう。

Font Loading API を使用したフォント レンダリングの最適化

Font Loading API はスクリプティング インターフェースを提供するもので、CSS フォント フェイスを定義および操作すること、それらのダウンロードの進行状況を追跡すること、デフォルトの遅延読み込み動作をオーバーライドすることが可能です。たとえば、特定の派生フォントが必要になることがわかっている場合に、その派生フォントを定義し、フォント リソースの取得を直ちに開始するようブラウザに指示することができます。

var font = new FontFace("Awesome Font", "url(/fonts/awesome.woff2)", {
  style: 'normal', unicodeRange:'U+000-5FF', weight:'400'
});

font.load(); // don't wait for the render tree, initiate an immediate fetch!

font.ready().then(function() {
  // apply the font (which may re-render text and cause a page reflow)
  // after the font has finished downloading
  document.fonts.add(font);
  document.body.style.fontFamily = "Awesome Font, serif";

  // OR... by default the content is hidden, 
  // and it's rendered after the font is available
  var content = document.getElementById("content");
  content.style.visibility = "visible";

  // OR... apply your own render strategy here... 
});

また、フォントの状態を(check() メソッドを通じて)確認し、ダウンロードの進行状況を追跡できるので、ページにテキストを表示するための独自の方法を定義することもできます。

  • フォントが使用可能になるまですべてのテキストの表示を保留できます。
  • フォントごとに独自のタイムアウトを実装できます。
  • 代替フォントを使用して表示の保留を解除し、フォントが使用可能になった時点で、目的のフォントを使用した新しいスタイルを表示できます。

特に、ページ上のさまざまなコンテンツに対して上記の方法を組み合わせることもできます。たとえば、「フォントが使用可能になるまで一部のセクションでテキストの表示を保留する」、「代替フォントを使用し、フォントのダウンロードが完了したら再表示する」、「さまざまなタイムアウトを指定する」などの方法を利用できます。

注: Font Loading API は、一部のブラウザではまだ開発段階ですFontLoader polyfill または webfontloader ライブラリを使用して同様の機能を提供することを検討してください。ただし、JavaScript への依存性が高まることによるオーバーヘッドがあります。

インライン化を利用したフォントの表示の最適化

Font Loading API を利用する代わりに、「空テキストの問題」を解消する単純な方法として、フォント コンテンツの CSS スタイルシートへのインライン化があります。

  • 一致するメディア クエリを持つ CSS スタイルシートは、ブラウザによって優先的に自動でダウンロードされます。これは、CSSOM の構築に必要であるためです。
  • フォント データを CSS スタイルシートにインライン化すると、ブラウザはレンダリング ツリーの構築を待つことなく、そのフォントを強制的に高い優先順位でダウンロードします。これは、デフォルトの遅延読み込み動作に対する手動の無効化として機能します。

インライン化方式はそれほど柔軟性がなく、コンテンツに合わせてカスタム タイムアウトやレンダリング方法を定義できませんが、単純で確実な解決策であり、すべてのブラウザで機能します。最適な結果を得るため、インライン化したフォントは単独のスタイルシートに分けておき、最大限の存続期間で利用してください。そうすることで、CSS を更新する際に訪問者にフォントの再ダウンロードを強制せずに済みます。

注: むやみにインライン化しないください。@font-face で遅延読み込み動作を採用しているのは、不要な派生フォントやサブセットのダウンロードを避けるためです。また、インライン化を過度に使用して CSS のサイズを増やすとクリティカル レンダリング パスに悪い影響を与えます。ブラウザではすべての CSS をダウンロードした後でないと、CSSOM を構築してレンダリング ツリーを作成し、ページ コンテンツを画面にレンダリングできません。

HTTP キャッシュを利用したフォントの再利用の最適化

フォント リソースは通常は静的なリソースであり、頻繁に更新されることはありません。そのため、max-age の有効期限を長く指定する対象として適しています。すべてのフォント リソースに対して条件付き ETag ヘッダー最適な Cache-Control ポリシーの両方を必ず指定してください。

フォントを localStorage やその他のメカニズムを利用して保存する必要はありません。こうしたメカニズムにはそれぞれパフォーマンスに関する複数の問題があります。 ブラウザの HTTP キャッシュと、Font Loading API または webfontloader ライブラリの組み合わせが、ブラウザにフォント リソースを提供するための最も確実で最適なメカニズムです。

最適化チェックリスト

一般的な理解に反して、ウェブフォントを利用することで必ずページのレンダリングが遅れたり、その他のパフォーマンス指標に悪影響が生じたりするわけではありません。適切に最適化されたフォントを利用すれば、全体的なユーザー エクスペリエンスを大幅に向上できます。優れたブランディング、読みやすさの向上、ユーザビリティ、検索機能を備えながら、あらゆる画面形式と解像度にうまく対応する、複数の解像度に対応した拡張可能なソリューションを提供できます。ウェブフォントを積極的に活用しましょう。

ただし、安易に実装すると、大量のダウンロードや不要な遅延を招くおそれがあります。そこで、ブラウザでフォント アセットを最適化し、それらを取得してページ上で利用する方法を最適化できるようにする必要があります。

  • フォントの利用を調査して監視する: ページ上でフォントを過度に使用しないようにし、フォントごとに使用する派生フォントの数を最小限に抑えます。こうすることで、ユーザー エクスペリエンスの一貫性が高まり、動作が高速になります。
  • フォント リソースをサブセット化する: 多数のフォントをサブセット化したり、複数の unicode-range に分割したりすることで、特定のページで必要なグリフだけを提供できます。その結果、ファイルサイズが減少し、リソースのダウンロード速度が速くなります。ただし、サブセットを定義する際はフォントの再利用を考慮して注意深く最適化してください。たとえば、ページごとに異なる文字セットをダウンロードする際、文字セットに重複が生じないようにします。スクリプト(ラテン、キリルなど)に基づいてサブセット化することをおすすめします。
  • ブラウザごとに最適化されたフォント形式を提供する: それぞれのフォントを WOFF2、WOFF、EOT、TTF の各形式で提供します。EOT 形式と TTF 形式はデフォルトで圧縮されないため、必ず GZIP 圧縮を適用します。
  • 再検証と最適なキャッシュ ポリシーを指定する: フォントは静的なリソースであり、頻繁に更新されることはありません。サーバーで長期間にわたって最大限存続させるようにします。また、再検証トークンを用意して、異なるページ間でフォントが効率よく再利用されるようにします。
  • Font Loading API を使用してクリティカル レンダリング パスを最適化する: デフォルトの遅延読み込み動作では結果的にテキストのレンダリングが遅れる場合があります。Font Loading API を使うと特定のフォントに対してこの動作をオーバーライドでき、ページ上のさまざまなコンテンツに対してカスタムのレンダリング方法やタイムアウトを指定できます。この API をサポートしていない旧式のブラウザには、Web Font Loader JavaScript ライブラリを利用するか、CSS インライン化による方法を利用できます。