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

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 は、フォントの指標のオーバーライドを使用する代替フォントを自動的に生成して挿入するライブラリです。
  • このリポジトリには、Google Fonts でホストされているすべてのフォントのフォント指標のオーバーライドが含まれています。これらの値は、コピーしてスタイルシートに貼り付けることができます。

背景

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

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

代替フォントを使用すると、(font-display: swap を使用して)テキストをより迅速にレンダリングできます。その結果、ページ コンテンツが読みやすく、役立ちます。ただし、これまでのところ、レイアウトが不安定になります。代替フォントがウェブフォントにスワップアウトされると、レイアウトの移動がよく発生します。ただし、以下で説明する新しい API を使用すると、ウェブフォントと同じ容量を占有する代替フォント フェースを作成できるため、この問題を軽減または排除できます。

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

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

フォント指標のオーバーライドの仕組み

はじめに

フォント指標のオーバーライドを使用すると、フォントの昇順、降順、ラインギャップをオーバーライドできます。

  • [Ascent] は、フォントのグリフがベースラインから最も遠くまで延びる距離を測定します。
  • [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 メニューを選択します。

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

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

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

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

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

クロスデバイスの互換性

大部分のフォント(たとえば、Google Fonts でホストされているフォントの約 90%)では、ユーザーのオペレーティング システムを知らなくてもフォント指標のオーバーライドを安全に使用できます。つまり、これらのフォントでは、hheatypowin の指標が適用されても、ascent-overridedescent-overridelinegap-override の値はまったく同じままです。このリポジトリでは、どのフォントがどのフォントに適用されるか、または適用されないかについて説明しています。

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 と font-metric のオーバーライドを計算する

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 は Sans Serif フォントの推奨される代替フォントで、Times New Roman は Serif フォントの推奨代替フォントです。ただし、どちらのフォントも Android では使用できません(Android の唯一のシステム フォントは Roboto です)。

下記の例では、幅広いデバイスに対応できるよう、3 つの代替フォント(Windows/Mac デバイスを対象とする代替フォント、Android デバイスを対象とする代替フォント、汎用フォント ファミリーを使用する代替フォント)を使用しています。

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 の使用に関してフィードバックがございましたら、お問い合わせください。