デザイナー指定の数字・記号だけを本文フォントに混植したいときの解決策。
✅ 数字だけ字形が合わない、を混植で解決する考え方
✅ Google Fontsのtext=パラメータでは解決できない理由
✅ FontToolsでの数字専用サブセット化のポイント(詳細は関連記事)
✅ size-adjustでのベースライン調整(詳細は関連記事)
✅ npm公開からunpkg/jsDelivr配信までの実際の手順
FontToolsでRoboto数字専用サブセットを作成し、size-adjustでベースラインを整え、npm経由でjsDelivr配信するまでの手順を実例付きで解説します。
1. きっかけ:数字とJ/jだけ字形が合わない
本文フォントにはKumbh SansやHanken Grotesk、Overused Groteskのようなモダンなグロテスク体を使うことが多いのですが、デザインカンプと突き合わせると、数字と一部の記号、J/jだけ字形の印象が違う場面が繰り返し出てきました。
0123456789の字形はフォントごとの個性が強く出やすい部分で、桁区切りのハイフンの字形が独特なGaramond系フォントや、1の下に横棒が入るかどうかなど、デザイナーの意図と食い違いやすい箇所です。J/j も同様で、Robotoの J/j はHelvetica寄りですが、Kumbh SansやHanken Grotesk、Overused Groteskではより主張の強いデザインになっています。

本文全体をRobotoに差し替えるわけにはいかないので、「数字と一部の記号、J/jだけをRobotoにする」という運用を考えました。
2. Google Fontsのtext=パラメータでは解決できない
最初に検討したのは、Google FontsのCSS2 APIのtext=パラメータで文字を絞り込む方法でした。
<link
href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700;800&display=swap&text=..."
rel="stylesheet"
media="print"
onload="this.media='all'"
>
指定した文字だけを持つフォントを取得できるので、font-family: 'Roboto', 'Kumbh Sans'のようなスタックにすれば、J/j以外は自動的にKumbh Sansへフォールバックします。理屈のうえではこれでも成立します。
ですが、GoogleのCSS2 APIが返す@font-faceは編集できないため、size-adjustを追加できません。 Google Fontsに乗せている限りこの調整ができず、結局自前ホストが必須になります(size-adjustの考え方については関連記事「size-adjustで日本語と英語フォントのバランスを調整」を参照)。
CSS:size-adjustで日本語と英語フォントのバランスを調整する -実例で完全解説-
なおtext=パラメータをURLに直書きする場合、&や<、>などの記号はパーセントエンコードしないとクエリが途中で切れるので注意してください。
3. 方針:文字種ごとのサブセットフォントを自作する
自前ホストに決めたので、次は「どの文字を含めるか」の設計です。今回作成したのはNumericサブセット(数字+半角記号+J/j)で、対象書体はRobotoです。
収録文字は以下の45文字にしました。
¥0123456789!"#$%&'()*+,-./:;<=>?@[]^_`{|}~jJ
半角記号を含めているのはGaramondのようにハイフンの字形が特殊なフォントがあるため、J/jを含めているのはRobotoの字形がHelvetica寄りで好みに合うためです。unicode-rangeにすると以下になります。
unicode-range: U+0021-0040, U+004A, U+005B-0060, U+006A, U+007B-007E, U+00A5;

4. FontToolsでサブセット化する
サブセット化にはfonttools(WOFF2化にはbrotli)を使います。Pythonのインストールからサブセット化コマンドまでの詳細は関連記事「Pythonの「FontTools」でサブセット化」にまとめています。
Pythonの「FontTools」で、font-feature-settingが効くフォントのサブセット化
5. size-adjustでベースラインを揃える
数字専用フォントも、本文フォント(Kumbh Sansなど)とのサイズ感を揃えるためにsize-adjustを使います。考え方と調整値の決め方は関連記事「size-adjustで日本語と英語フォントのバランスを調整」の通りで、今回は組み合わせる本文フォントに対して106%を設定しました。
@font-face {
font-family: "Roboto Numeric";
src: url("Roboto-Numeric-Regular.woff2") format("woff2");
font-style: normal;
font-weight: 400;
size-adjust: 106%;
font-display: swap;
unicode-range: U+0021-0040, U+004A, U+005B-0060, U+006A, U+007B-007E, U+00A5;
}
size-adjust版とオリジナル版の2つのCSSを用意し、案件によって使い分けられるようにしています。
なお、対応ブラウザはIE11とSafari 9以前を除けば全てwoff2をサポートしているため、woff形式は同梱していません。
CSS:size-adjustで日本語と英語フォントのバランスを調整する -実例で完全解説-
6. npmで公開してCDN配信する
サブセットフォントができたら、npmパッケージとして公開します。手順の詳細は関連記事「unpkg.comにWebフォントをアップロード」にまとめています。
npm/unpkg.comにWebフォントをアップロードする方法 -失敗例・注意点・実例付き-
npm login
npm publish --access public
公開後は、unpkgまたはjsDelivrのURLでそのまま読み込めます。
<link
href="https://cdn.jsdelivr.net/npm/@sarap422/font-roboto-numeric@1.0.6/font-face.adjusted.css"
rel="stylesheet"
>
unpkgからjsDelivrに切り替えた
当初はunpkgを使っていましたが、jsDelivrに切り替えました。
- unpkgはボランティアホスティングでSLAがない。過去に数時間規模の障害も起きており、落ちるとクライアントサイトの数字表示が全部フォールバックしてしまうリスクがある
- jsDelivrは商用CDN基盤の上でnpmパッケージをそのまま配信できる。追加のアップロード作業は不要で、URLの
unpkg.comをcdn.jsdelivr.net/npmに書き換えるだけで切り替わる
まとめ
- 数字や
J/jだけ本文フォントと字形が合わない問題は、CSSのfont-familyスタックによるグリフ単位の混植で解決できる - Google Fontsの
text=パラメータでも文字は絞れるが、size-adjustが使えないため自前ホストが必要になる - サブセット化は文字を明示的に列挙する。範囲指定でまとめると意図せず余計な文字が残る
size-adjustでベースラインを揃え、npm公開してunpkg/jsDelivrで配信する- CDNはSLAの有無を基準にjsDelivrを選ぶ
関連記事
Pythonの「FontTools」で、font-feature-settingが効くフォントのサブセット化
CSS:size-adjustで日本語と英語フォントのバランスを調整する -実例で完全解説-
npm/unpkg.comにWebフォントをアップロードする方法 -失敗例・注意点・実例付き-