技術 約6分で読めます

lilting.chの本文フォントをGeistからGen Interface JPに差し替えた

いけさん目次

lilting.ch の本文フォントをそろそろ入れ替えたい。
いまは BaseLayout.astro で Google Fonts の Geist と Geist Mono を読み込んでいて、本文もそのまま font-sans に乗っている。
英数字の見え方は悪くないが、日本語本文を読むサイトとしては少し欧文側に寄っている。

Gen Interface JP はその隙間にちょうど入る候補だった。
公式サイトの説明は「デジタルインターフェース」のための和欧混植フォントという位置づけで、欧文と和文の調和を狙う書体になっている。
Parascope の Gen Interface JP紹介ページ でも、Inter と Noto Sans JP を組み合わせ、UI上で欧文と日本語の見え方を揃えるフォントとして紹介されていた。

Interっぽさを残したまま日本語を読ませる

自分のサイトで欲しいのは、和文だけが急に重く見えない本文フォントだ。
日本語ブログで欧文フォントを前面に置くと、コード名、製品名、英語の略語は締まる。
その一方で、本文の日本語がフォールバックの Noto Sans JP へ流れ、字面のテンションが切り替わる。

Gen Interface JP は、そこを最初から混ぜてある。
欧文側の気配は Inter に近く、日本語側は Noto Sans JP をベースにしたUI向けの見え方へ寄せている。
「欧文だけかっこいいサイト」ではなく、日本語本文と製品名が同じ画面密度で並ぶことを狙うなら、かなり素直な選択肢に見える。

Claude CodeのUI出力を劇的に改善する3つのリソースでは、AIにUIを作らせるときのフォント選びについて少し触れた。
あの記事では「Inter、Roboto、Arial、システムフォントを避けろ」という文脈だったが、ブログ本体は奇抜なディスプレイフォントで遊ぶ場所ではない。
日本語の長文を読みやすくしつつ、UI部品の英数字も浮かせないほうが大事だ。

8ウェイトあるのでサイト全体へ当てやすい

ウェイトは Thin、ExtraLight、Light、Regular、Medium、SemiBold、Bold、ExtraBold の8段階。
本文、日付、タグ、カード見出し、ナビゲーション、TOCの見出しで太さを分けても不足しない。

このサイトだと、本文は Regular、カード見出しとナビゲーションは Medium、記事タイトルは SemiBold くらいで足りそうだ。
Bold以上は強調や大見出し用に残せる。
今の font-medium 多用も、そのまま置き換えて破綻しにくい。

ただし、全ウェイトを雑に読み込むとWebフォントとしては重い。
公式サイトは jsDelivr から all.css を読み込む例を出しているが、サイト全体へ入れるなら実際に使うウェイトだけに絞るか、セルフホストしてプリロードを調整したほうがよさそうだ。

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gen-interface-jp@0.1.2/all.css">

後でCSS差し替えの記事を足すなら、ここが本題になる。
Astro側のスタイル適用範囲は以前 AIはAstroのスコープドCSSがJavaScriptで生成した要素に適用されない事を忘れる で書いた話とも絡むが、今回はサイト全体のベースフォントなので BaseLayout.astro とグローバルCSS側の整理になるはず。

OFLなのでブログの通常利用では扱いやすい

ライセンスは SIL Open Font License 1.1。
npm パッケージのメタデータでも OFL-1.1 になっている。
Webフォントとしてブログに読み込む用途なら、扱いにくい商用フォント契約とはだいぶ違う。

ParascopeのSUMMARYでは、組み込み機器向けにビットマップ変換した場合もライセンスが引き継がれる、と補足されていた。
このサイトではそこまで踏み込まないが、Web以外へ持ち出すときも「フォントファイルをどう再配布しているか」は見る。

v0.1.1紹介のあとにv0.1.2が出ていた

ここだけメモしておく。
Parascopeの紹介ページは2026年5月6日公開で、SUMMARY内では GitHub Releases の v0.1.1 に触れている。
ただ、2026年5月7日 JST に確認した時点では、公式サイトのCSS読み込みは gen-interface-jp@0.1.2 になっていた。
npm の latest も 0.1.2、GitHub Releases でも Gen Interface JP v0.1.2 が公開済みだった。

v0.1.2 のリリースノートは、静的ウェイトの STAT 情報を修正するために ofl-font-baker を 0.3.6 へ上げた、という内容だ。
フォント選定の記事としては地味だが、ブラウザやデザインツールがフォントのウェイト情報をどう読むかに関係する。
今から入れるなら v0.1.1 ではなく v0.1.2 を見る。

CDN直で差し替えた

セルフホストは後回しにして、いまのGoogle Fonts読み込みと同じ流れで jsDelivr 直に置き換えた。
本文側のサンスだけ Gen Interface JP に寄せて、コードブロックの Geist Mono はそのまま残す方針にした。

BaseLayout.astro のフォント読み込みを必要ウェイトだけに絞る。

<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gen-interface-jp@0.1.2/400.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gen-interface-jp@0.1.2/500.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gen-interface-jp@0.1.2/600.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gen-interface-jp@0.1.2/700.css" />
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono&display=swap" rel="stylesheet" />

all.css を読まないのは、全Unicode範囲+全ウェイトで1.6MB級になるため。
ウェイトは本文の400と、Tailwindの font-medium font-semibold font-bold に対応する500/600/700の4つに絞った。
あとから不足を感じたウェイトだけ足していけばいい。

globals.css--font-sans も先頭だけ入れ替える。Geist用のフォールバックを外し、和文側のフォールバックチェーンはそのまま残した。

--font-sans: 'Gen Interface JP', 'Hiragino Kaku Gothic ProN', 'Hiragino Sans', 'Noto Sans JP', sans-serif;

第一印象としては、思っていたより少しパキッとした。
Geistのときより字形のエッジがしっかり出ていて、英数字と日本語の濃度がほぼ揃って並ぶ。
ただ、これは差し替え直後の短時間の印象でしかないので、しばらく自分のサイトを巡回してみてから、本文の読み心地として残すかどうかを判断する。

追記: Vercelに /w/normal/... の404が大量に飛んできた

差し替えから数時間で、Vercelから「/w/normal/600/059.woff2 のような存在しないパスへの404が2500件超える勢いで叩かれている」というアラートが来た。
パスに心当たりがなかったので最初はBotスキャンを疑ったが、原因はこちら側だった。

jsDelivrから配信される gen-interface-jp@0.1.2/600.css などの @font-face は、woff2を相対パスで参照している。

@font-face {
  font-family: "Gen Interface JP";
  font-weight: 600;
  src: url("./w/normal/600/000.woff2") format("woff2");
  /* ... */
}

正規のブラウザはCSSファイルの場所(jsDelivr)を基準にURLを解決するので、本物のフォントは cdn.jsdelivr.net/npm/gen-interface-jp@0.1.2/w/normal/600/000.woff2 に正しく取りに行く。
ところがCSSの中身を雑に正規表現で抜くだけのクローラーや、相対URL解決の実装が甘いツールは、url("./w/...") を閲覧元ドメイン基準で解いてしまう。結果として lilting.ch/w/normal/600/000.woff2 を叩いて404になる。

Gen Interface JP は文字をUnicodeブロック単位で細かくサブセット分割しているので、CSS 1ファイルあたり数十〜100個近いwoff2参照が並ぶ。1ページ表示で数百404にスケールするBotがいると、すぐに2500件オーダーまで膨れる。

実害はないが、Vercelのアラートと帯域がうるさいので vercel.json/w/* を jsDelivr の本来のパスへリダイレクトすることにした。Botにも本物のwoff2が返るので副作用はない。

{
  "redirects": [
    {
      "source": "/w/:path*",
      "destination": "https://cdn.jsdelivr.net/npm/gen-interface-jp@0.1.2/w/:path*",
      "permanent": false
    }
  ]
}

permanent: false(302)にしているのは、フォントのバージョンを上げたときにキャッシュで古いパスへ縛られないようにするため。
セルフホストすればこの問題は根本的に消えるが、woff2が数百ファイル単位で増えるのでひとまず保留にしている。

参考