フォントの代替機能の改善

Katie Hempenius
Katie Hempenius

概要

この記事では、フォント フォールバックと size-adjustascent-overridedescent-overrideline-gap-override API について詳しく説明します。これらの API を使用すると、ローカルフォントを使用して、ウェブフォントの大きさに近い、または完全に一致する代替フォントフェイスを作成できます。これにより、フォント スワップによるレイアウトのずれを軽減または排除できます。

この記事を読むのが面倒な場合は、以下のツールを使用してこれらの API をすぐに使用できます。

フレームワーク ツール:

  • @next/font: Next 13 以降、next/font はフォント指標のオーバーライドと size-adjust を自動的に使用して、一致するフォント フォールバックを提供します。
  • @nuxtjs/fontaine: Nuxt 3 以降では、nuxt/fontaine を使用して、Nuxt アプリで使用されるスタイルシートに一致するフォント フォールバックが自動的に生成され、挿入されます。

フレームワーク以外のツール:

  • Fontaine: Fontaine は、フォント メトリックのオーバーライドを使用するフォント フォールバックを生成し、自動的に挿入するライブラリです。
  • このrepoには、Google Fonts でホストされているすべてのフォントに対するフォント指標のオーバーライドが含まれています。これらの値はコピーしてスタイルシートに貼り付けることができます。

背景

代替フォントは、プライマリ フォント フェースがまだ読み込まれていない場合や、ページ コンテンツのレンダリングに必要なグリフが不足している場合に使用されるフォント フェースです。たとえば、次の CSS は、"Roboto" の代替フォントとして sans-serif フォント ファミリーを使用することを示しています。

font-family: "Roboto" , sans-serif;

代替フォントを使用すると、テキストをより速くレンダリングできます(font-display: swap を使用)。その結果、ページ コンテンツをより早く読みやすく、有用にすることができます。ただし、これまでは、レイアウトの不安定さがその代償となっていました。代替フォントがウェブフォントと入れ替わると、レイアウトがずれるのが一般的でした。ただし、後述する新しい API を使用すると、ウェブフォントと同じ量のスペースを占有する代替フォントフェイスを作成できるため、この問題を軽減または排除できます。

フォント フォールバックの改善

「改善された」フォント フォールバックを生成する方法は 2 つあります。よりシンプルな方法では、フォント指標のオーバーライド API のみを使用します。より複雑(ただしより強力)な方法では、フォント メトリック オーバーライド API と size-adjust の両方を使用します。この記事では、これらのアプローチの両方について説明します。

フォント メトリック オーバーライドの仕組み

はじめに

フォント指標のオーバーライドを使用すると、フォントの上昇、下降、行間隔をオーバーライドできます。

  • 上昇は、フォント グリフがベースラインから上方に延びる最長距離を測定します。
  • Descent は、フォント グリフがベースラインの下方に延びる最長距離を測定します。
  • 行間隔(「行間」とも呼ばれます)は、連続するテキスト行間の距離を測定します。

フォントの上昇、下降、行間隔を示す図。

フォント指標のオーバーライドを使用すると、代替フォントの上昇、下降、行間隔をオーバーライドして、ウェブフォントの上昇、下降、行間隔と一致させることができます。その結果、ウェブフォントと調整済みの代替フォントは常に同じ縦方向の寸法になります。

フォント メトリックのオーバーライドは、次のようなスタイルシートで使用されます。

body {
    font-family: Poppins, "fallback for poppins";
}

@font-face {
    font-family: "fallback for poppins";
    src: local("Times New Roman");
    ascent-override: 105%;
    descent-override: 35%;
    line-gap-override: 10%;
}

この記事の冒頭に記載されているツールを使用すると、正しいフォント メトリック オーバーライド値を生成できます。ただし、これらの値は自分で計算することもできます。

フォント指標のオーバーライドの計算

次の式は、特定のウェブフォントに対するフォント指標のオーバーライドを生成します。フォント メトリック オーバーライドの値は、小数ではなくパーセンテージ(例: 105%)で指定する必要があります。

ascent-override = ascent/unitsPerEm
descent-override = descent/unitsPerEm
line-gap-override = line-gap/unitsPerEm

たとえば、Poppins フォントの場合、フォント指標のオーバーライドは次のようになります。

/*
Poppins font metrics:
ascent = 1050
descent = 350
line-gap = 100
UPM: 1000
*/

ascent-override: 105%;  /* = 1050/1000 */
descent-override: 35%;  /* = 350/1000 */
line-gap-override: 10%; /* = 100/1000 */

ascentdescentline-gapunitsPerEm の値はすべて、ウェブフォントのメタデータから取得されます。この記事の次のセクションでは、これらの値を取得する方法について説明します。

フォント テーブルの読み取り

フォントのメタデータ(特にフォント テーブル)には、フォント指標のオーバーライドの計算に必要なすべての情報が含まれています。

FontForge の [フォント情報] ダイアログ ボックスのスクリーンショット。ダイアログ ボックスには、「Typo Ascent」、「Typo Descent」、「Typo Line Gap」などのフォント メトリックが表示されます。
FontForge を使用してフォント メタデータを表示する

フォントのメタデータを読み取る際に使用できるツールは次のとおりです。

  • fontkit は、Node.js 用に構築されたフォント エンジンです。次のコード スニペットは、fontkit を使用してフォント メトリックのオーバーライドを計算する方法を示しています。
  • Capsize は、フォントサイズとレイアウトのライブラリです。Capsize には、さまざまなフォント メトリックに関する情報を取得するための API が用意されています。
  • fontdrop.info は、ブラウザからフォントテーブルなどのフォント関連情報を確認できるウェブサイトです。
  • Font Forge は、一般的なデスクトップ フォント エディタです。ascentdescentline-gap を表示するには、Font Info ダイアログを開き、OS/2 メニューを選択して、[Metrics] タブを選択します。UPM を表示するには: Font Info ダイアログを開き、General メニューを選択します。

フォント テーブルについて

「上昇」などのコンセプトは、複数の指標で参照されていることに気付くでしょう。たとえば、hheaAscenttypoAscentwinAscent の指標があります。これは、オペレーティング システムによってフォント レンダリングのアプローチが異なるためです。OSX デバイスのプログラムは通常 hhea* フォント メトリックを使用しますが、Windows デバイスのプログラムは通常 typo*sTypo* とも呼ばれます)または win* フォント メトリックを使用します。

フォント、ブラウザ、オペレーティング システムに応じて、フォントは hheatypowin のいずれかの指標を使用してレンダリングされます。

Mac Windows
Chromium 「hhea」テーブルの指標を使用します。 「USE_TYPO_METRICS」が設定されている場合は「typo」テーブルの指標を使用し、そうでない場合は「win」テーブルの指標を使用します。
Firefox 「USE_TYPO_METRICS」が設定されている場合は「typo」テーブルの指標を使用し、そうでない場合は「hhea」テーブルの指標を使用します。 「USE_TYPO_METRICS」が設定されている場合は「typo」テーブルの指標を使用し、そうでない場合は「win」テーブルの指標を使用します。
Safari 「hhea」テーブルの指標を使用します。 「USE_TYPO_METRICS」が設定されている場合は「typo」テーブルの指標を使用し、そうでない場合は「win」テーブルの指標を使用します。

オペレーティング システム間でのフォント指標の動作について詳しくは、縦方向の指標に関するこちらの記事をご覧ください。

クロスデバイスへの対応

ほとんどのフォント(Google Fonts でホストされているフォントの約 90% など)では、ユーザーのオペレーティング システムを知らなくてもフォント メトリックのオーバーライドを安全に使用できます。つまり、これらのフォントでは、hheatypowin のいずれのメトリックが適用されるかにかかわらず、ascent-overridedescent-overridelinegap-override の値はまったく同じになります。このrepoには、この制限が適用されるフォントと適用されないフォントに関する情報が記載されています。

OSX デバイスと Windows デバイスで別々のフォント メトリック オーバーライド セットを使用する必要があるフォントを使用している場合は、ユーザーのオペレーティング システムに基づいてスタイルシートを変更できる場合にのみ、フォント メトリック オーバーライドと size-adjust を使用することをおすすめします。

フォント指標のオーバーライドの使用

フォント指標のオーバーライドは、ウェブフォントのメタデータ(フォールバック フォントではなく)から取得した測定値を使用して計算されるため、フォールバック フォントとして使用されるフォントが変わっても変わりません。次に例を示します。

body {
  font-family: "Poppins", "fallback for Poppins", "another fallback for Poppins";
}

@font-face {
  font-family: "fallback for Poppins";
  src: local("Arial");
  ascent-override: 105%;
  descent-override: 35%;
  line-gap-override: 10%;
}

@font-face {
  font-family: "another fallback for Poppins";
  src: local("Roboto");
  ascent-override: 105%;
  descent-override: 35%;
  line-gap-override: 10%;
}

サイズ調整の仕組み

はじめに

size-adjust CSS 記述子は、フォント グリフの幅と高さを比例してスケーリングします。たとえば、size-adjust: 200% はフォント グリフを元のサイズの 2 倍に拡大し、size-adjust: 50% は元のサイズの半分に縮小します。

「size-adjust: 50%」と「size-adjust: 200%」を使用した場合の結果を示す図。

size-adjust だけでは、フォントのフォールバック改善の適用は限られます。ほとんどの場合、ウェブフォントと一致させるには、フォールバック フォントを(比例縮小ではなく)少し狭めたり広げたりする必要があります。ただし、size-adjust とフォント メトリック オーバーライドを組み合わせることで、任意の 2 つのフォントを水平方向と垂直方向の両方で一致させることができます。

スタイルシートで size-adjust を使用する方法は次のとおりです。

@font-face {
  font-family: "fallback for poppins";
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

size-adjust の計算方法(次のセクションで説明)により、size-adjust の値(および対応するフォント指標のオーバーライド)は、使用される代替フォントによって異なります。

body {
  font-family: "Poppins", "fallback for Poppins", "another fallback for Poppins";
}

@font-face {
  font-family: poppins-fallback;
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

@font-face {
  font-family: poppins-fallback-android;
  src: local("Roboto");
  size-adjust: 55.5193474%:
  ascent-override: 180.1173909%;
  descent-override: 63.04108683%;
  line-gap-override: 18.01173909%;
}

サイズ調整とフォント指標のオーバーライドの計算

size-adjust とフォント指標のオーバーライドを計算する式は次のとおりです。

size-adjust = avgCharacterWidth of web font / avgCharacterWidth of fallback font
ascent-override = web font ascent / (web font UPM * size-adjust)
descent-override = web font descent / (web font UPM * size-adjust)
line-gap-override = web font line-gap / (web font UPM * size-adjust)

これらの入力のほとんど(上昇、下降、行間)は、ウェブフォントのメタデータから直接読み取ることができます。ただし、avgCharacterWidth は近似する必要があります。

平均文字幅の近似

一般に、平均文字幅は近似値でしか求めることができませんが、固定幅フォントを使用している場合や、テキスト文字列の内容が事前にわかっている場合など、正確に計算できるシナリオもあります。

avgCharacterWidth を計算するナイーブな方法の例として、すべての [a-z\s] 文字の平均幅を取得する方法があります。

 個々の Roboto [a-zs] グリフの幅を比較したグラフ。
Roboto グリフの幅

ただし、すべての文字に同じ重み付けをすると、よく使用される文字(e など)の幅が小さくなり、使用頻度の低い文字(z など)の幅が大きくなる可能性があります。

精度を高めるには、文字の頻度を考慮して、[a-z\s] 文字の頻度加重平均幅を計算する、より複雑なアプローチもあります。英語のテキストの文字頻度と平均単語長については、こちらの記事を参照してください。

英語の文字頻度を示すグラフ。
英語の文字頻度

アプローチの選択

この記事で説明する 2 つのアプローチには、それぞれにメリットとデメリットがあります。

  • フォント フォールバックの最適化を開始する場合は、フォント指標のオーバーライドのみを使用することをおすすめします。これは 2 つのアプローチの中ではシンプルですが、通常はフォント関連のレイアウト シフトの度合いを大幅に軽減するのに十分な効果があります。

  • 一方、精度を高め、もう少し作業とテストを行うことをいとわない場合は、size-adjust を組み込むことをおすすめします。このアプローチを正しく実装すると、フォント関連のレイアウト シフトを効果的に排除できます。

代替フォントの選択

この記事で説明する手法では、ウェブフォントに近いローカルフォントを見つけるのではなく、フォント メトリック オーバーライドと size-adjust を使用して、広く利用可能なローカルフォントを変換します。ローカル フォントを選択する際は、ローカルで広く利用されているフォントはごくわずかであり、すべてのデバイスに存在するフォントは 1 つもないことを念頭に置くことが重要です。

Arial はサンセリフ フォント用の推奨代替フォントであり、Times New Roman はセリフ フォント用の推奨代替フォントです。ただし、これらのフォントはどちらも Android では使用できません(Android で使用できるシステム フォントは Roboto のみです)。

次の例では、Windows/Mac デバイスをターゲットとする代替フォント、Android デバイスをターゲットとする代替フォント、汎用フォント ファミリーを使用する代替フォントの 3 つの代替フォントを指定して、幅広いデバイスに対応しています。

body {
  font-family: "Poppins", poppins-fallback, poppins-fallback-android, sans-serif;
}

/*
Poppins font metrics:
- ascent = 1050
- descent = 350
- line-gap = 100
- UPM: 1000
AvgCharWidth:
- Poppins: 538.0103768
- Arial: 884.1438804
- Roboto: 969.0502537
*/

@font-face {
  font-family: poppins-fallback;
  src: local("Arial");
  size-adjust: 60.85099821%;
  ascent-override: 164.3358416%;
  descent-override: 57.51754455%;
  line-gap-override: 16.43358416%;
}

@font-face {
  font-family: poppins-fallback-android;
  src: local("Roboto");
  size-adjust: 55.5193474%:
  ascent-override: 180.1173909%;
  descent-override: 63.04108683%;
  line-gap-override: 18.01173909%;
}

フィードバックのお願い

フォント指標のオーバーライドと size-adjust の使用に関するフィードバックがございましたら、お知らせください。