Claude CodeでWebフォント最適化を実装する実践ガイド
Claude CodeでWebフォントを速く安定して読み込む実装手順。CLS/LCP、preload、サブセット化まで解説。
フォント最適化は見た目の話だけではない
Webフォントはブランドの印象を整えますが、読み込み方を間違えると、本文が一瞬消える、見出しが後からずれる、Largest Contentful Paint、つまり画面内の最大要素が表示されるまでの時間が悪化する、といった問題を起こします。特に日本語フォントはファイルが大きくなりやすく、何となくGoogle Fontsを読み込むだけでは、LCPとCLSの両方に効いてしまいます。
この記事では、Claude Codeを使ってWebフォント最適化を安全に実装する手順を、Astroサイトを例に整理します。preload、preconnect、font-display、可変フォント、サブセット化、セルフホストとサードパーティ配信の判断、LighthouseやWebPageTest風のウォーターフォール確認まで扱います。
用語を先にそろえます。font-displayは、フォントがまだ届いていない間に文字をどう表示するかを決める@font-faceの記述子です。MDNのfont-display解説では、swapやoptionalなどの挙動が説明されています。preloadは、すぐ必要になるリソースを早く取りに行くためのヒントで、MDNのrel="preload"解説ではフォントにはcrossoriginが必要だと説明されています。フォント最適化の全体像はweb.devのBest practices for fontsとOptimize web fontsが基準になります。
最初にフォント戦略を決める
Claude Codeにいきなり「フォントを速くして」と頼むと、不要なpreloadを増やしたり、デザインで使っている重みを消したりすることがあります。先に「どの文字を、どの画面で、どの優先度で見せるか」を決めます。
| ユースケース | 推奨戦略 | 理由 | 落とし穴 |
|---|---|---|---|
| 日本語ブログの本文 | システムフォントを第一候補にし、ブランド見出しだけWebフォント | 本文量が多く、全ページで日本語フォントを読むと重い | 見出し用フォントを本文にも適用してしまう |
| SaaS管理画面 | Interなどの可変フォントをセルフホスト | 400から700まで1ファイルで扱いやすい | 使わない斜体や全言語グリフまで配信する |
| LPのファーストビュー | LCP見出しに使う1ファイルだけpreload | ヒーロー文言の表示が売上に直結する | 使われない太字まで先読みして帯域を食う |
| アイコンフォント | SVGアイコンへ置き換える | 文字フォントと別の読み込み競合を減らせる | 既存CSSの疑似要素が壊れる |
ここで重要なのは、フォントを「全部速くする」のではなく、ページの最初に見える文字だけを確実に早くすることです。本文が長い記事なら、まずシステムフォントで読める状態にして、ブランド性が必要な見出しだけWebフォントにします。SaaSなら、英数字中心のUIに可変フォントを使い、Noto Sans JPのような大きな日本語フォントは必要な画面だけに限定します。
関連する画像のLCP対策はClaude Code画像最適化ガイドと合わせて見ると判断しやすくなります。全体の速度改善はClaude Codeパフォーマンス最適化にもつながります。
Astroでpreloadとpreconnectを実装する
preloadは強いヒントです。便利ですが、使いすぎるとCSS、画像、JavaScriptより先に不要なフォントを取りに行き、かえってLCPを悪化させます。原則は「ファーストビューで実際に使う、1から2個のwoff2だけ」です。サードパーティのGoogle Fontsを使う場合だけ、CSS配信用ドメインとフォント配信用ドメインにpreconnectを置きます。セルフホストなら通常はpreconnectは不要です。
Astroのベースレイアウトなら、次のように読み込み先を明示します。
---
// src/layouts/BaseLayout.astro
const criticalFonts = [
{ href: "/fonts/inter-var-latin.woff2", type: "font/woff2" },
{ href: "/fonts/noto-sans-jp-latin-kana.woff2", type: "font/woff2" },
];
const usesGoogleFonts = false;
---
<html lang="ja">
<head>
{criticalFonts.map((font) => (
<link rel="preload" href={font.href} as="font" type={font.type} crossorigin />
))}
{usesGoogleFonts && <link rel="preconnect" href="https://fonts.googleapis.com" />}
{usesGoogleFonts && <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />}
<link rel="stylesheet" href="/styles/fonts.css" />
</head>
<body>
<slot />
</body>
</html>
確認ポイントは3つです。1つ目はhrefが実際の@font-faceのsrcと一致していること。2つ目はas="font"、type="font/woff2"、crossoriginがそろっていること。3つ目は、preloadしたフォントが数秒以内に本当に使われることです。Chrome DevToolsで「preloaded but not used」という警告が出るなら、先読み対象を減らします。
font-displayとフォールバックメトリクスを整える
font-display: swapは、最初に代替フォントで文字を表示し、Webフォントが届いたら差し替える設定です。白紙時間、つまりFOITを避けやすい一方、代替フォントとWebフォントの字幅や行高が大きく違うと、差し替え時にCLSが発生します。optionalは、遅い回線でWebフォントを諦めやすくするため、本文や小さなUIに向くことがあります。
次のCSSは、英数字UIの可変フォント、日本語サブセット、フォールバック調整をまとめた例です。
/* public/styles/fonts.css */
@font-face {
font-family: "InterVariable";
src: url("/fonts/inter-var-latin.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "NotoSansJPSubset";
src: url("/fonts/noto-sans-jp-latin-kana.woff2") format("woff2");
font-weight: 400 700;
font-style: normal;
font-display: swap;
unicode-range: U+0000-00FF, U+3000-30FF, U+FF00-FFEF;
}
@font-face {
font-family: "InterFallback";
src: local("Arial");
size-adjust: 107%;
ascent-override: 90%;
descent-override: 22%;
line-gap-override: 0%;
}
:root {
--font-ui: "InterVariable", "InterFallback", system-ui, sans-serif;
--font-ja: "NotoSansJPSubset", "Hiragino Sans", "Yu Gothic", sans-serif;
}
body {
font-family: var(--font-ui);
}
article {
font-family: var(--font-ja);
}
unicode-rangeは、そのフォントが担当する文字範囲を指定する@font-face記述子です。MDNのunicode-range解説を基準に、ラテン、かな、漢字などに分けます。ただし、分けすぎるとHTTPリクエストが増えます。日本語サイトでは「英数字とかなだけを最初に読む」「漢字は本文CSSで遅れて読む」のように、ページの実態に合わせます。
可変フォントとサブセット化で配信量を減らす
可変フォントは、複数の太さや幅を1つのファイルにまとめられるフォントです。400、500、700を別ファイルで読むより管理が楽になり、UIで使う重みが多い場合に効きます。ただし、可変フォントだから常に小さいわけではありません。使う軸と文字範囲を確認し、必要ならサブセット化します。
サブセット化は、フォントから必要な文字だけを抜き出す作業です。日本語では特に効果がありますが、記事本文の漢字を取りこぼすと文字化けではなく「一部だけ別フォント」になります。公開前に代表ページで確認します。
# vendor-fonts/NotoSansJP-Regular.ttf から英数字、記号、かなだけをwoff2化する例
python -m pip install "fonttools[woff]"
mkdir -p public/fonts
pyftsubset ./vendor-fonts/NotoSansJP-Regular.ttf \
--output-file=./public/fonts/noto-sans-jp-latin-kana.woff2 \
--flavor=woff2 \
--layout-features='*' \
--unicodes="U+0000-00FF,U+3000-30FF,U+FF00-FFEF"
このコマンドは記事の全漢字を含みません。見出しやナビゲーションで使う文字だけを最初に軽く配る意図です。本文までWebフォントにしたいなら、ページ群から実際の文字を抽出して--text-fileを使うか、漢字用の別サブセットを用意します。Claude Codeには「どのファイルから文字を集めるか」「生成物をどこへ置くか」「ライセンスを変えないこと」を明示します。
セルフホストとサードパーティ配信を選ぶ
セルフホストは、フォントファイルを自分のpublic/fontsなどに置き、自サイトのキャッシュポリシーで配信する方式です。依存が少なく、preloadとキャッシュを合わせやすい一方、ライセンス、更新、サブセット生成を自分で管理します。サードパーティ配信は、Google FontsなどのCSSを読み込む方式です。導入は速いですが、外部接続、CSS取得、フォント取得が分かれるため、最初のリクエスト設計が重要になります。
| 判断軸 | セルフホスト | サードパーティ |
|---|---|---|
| 初回接続 | 自サイトだけで完結 | DNS、TLS、外部CSSが増える |
| キャッシュ制御 | 自分で長期キャッシュを設定できる | 提供元のヘッダーに従う |
| サブセット | 自由に作れる | APIや提供範囲に依存 |
| 運用 | ライセンスと更新確認が必要 | 導入は簡単だが外部依存が残る |
迷ったら、ファーストビューで使うフォントはセルフホスト、装飾的なフォントは読み込みを遅らせる、という分け方が堅実です。フォントのライセンスによってはセルフホストやサブセット化が制限されるため、作業前に必ず確認します。
LighthouseとWebPageTest風の確認を行う
実装後は、見た目だけでなくネットワークの順番を見ます。LighthouseはLCP、CLS、レンダリングブロック、font-displayの警告を見つける入口になります。Core Web Vitalsの定義はweb.devのWeb Vitalsが基準です。ラボ計測と実ユーザー計測はずれるため、公開後はSearch ConsoleやRUMの値も見ます。
URL="https://example.com/"
npx --yes lighthouse "$URL" \
--only-categories=performance \
--chrome-flags="--headless" \
--output=json \
--output-path=./lighthouse-fonts.json
node -e "const r=require('./lighthouse-fonts.json'); for (const id of ['largest-contentful-paint','cumulative-layout-shift','font-display']) console.log(id, r.audits[id]?.displayValue ?? r.audits[id]?.score ?? 'n/a')"
WebPageTest風に見るなら、ウォーターフォールで次を確認します。HTMLの後にCSSが来て、その後に必要なフォントだけが早く始まっているか。外部CSSとフォント本体で余計な待ち時間が出ていないか。同じwoff2が2回取得されていないか。モバイル低速設定でも本文が読めるか。フォント差し替え時に見出しやCTAボタンが動かないか。
失敗例も具体的に見ます。preloadした太字が実際にはページで使われていない。Google FontsのCSSとセルフホストCSSを両方残して二重読み込みしている。font-display: swapにしただけでフォールバックの字幅を合わせていない。日本語サブセットから長音、句読点、全角英数字が抜けている。こうした問題は見た目のレビューだけでは残りやすいです。
Claude Codeに安全に頼むプロンプト
Claude Codeには、調査、実装、検証を分けて頼むと安定します。最初のプロンプトでは編集を禁止し、フォントの使用箇所とネットワーク設計だけを出させます。
このAstroサイトのWebフォント読み込みを調査してください。まだ編集しないでください。
確認してほしいこと:
- @font-face、Google Fonts、Fontsource、CSS import の場所
- ファーストビューで実際に使うフォントファイル
- preload/preconnect の有無と過不足
- CLS/LCPに影響しそうなフォント差し替え
- セルフホスト化、可変フォント、サブセット化の候補
出力:
- 変更候補を優先度順に表で出す
- 触るべきファイルと触らないファイルを分ける
- 検証コマンドを提案する
実装を頼むときは、スコープと完了条件を固定します。
次のファイルだけを編集してWebフォント最適化を実装してください。
- src/layouts/BaseLayout.astro
- public/styles/fonts.css
- public/fonts/ 配下の生成物
要件:
- heroで使うwoff2だけをpreloadする
- サードパーティフォントを使わない場合はpreconnectを置かない
- @font-faceにはfont-displayを必ず指定する
- フォールバックメトリクスでCLSを抑える
- 既存のhero画像、slug、記事本文は触らない
検証:
- npm run build
- node scripts/check-code-fences.mjs
- LighthouseでLCPとCLSを確認
- 変更後に残るリスクを報告
実際に試した結果とCTA
Masaの運用では、最初から「フォントを軽くして」と頼むより、「LCP見出しに使うフォントだけを先読みし、本文はシステムフォントで読める状態にする」と指定した方が、差分が小さくなりました。特に日本語記事では、かなと英数字だけを先に読むサブセットにすると初回表示の安定感は上がりましたが、本文全体の見た目を完全にそろえるには追加の文字抽出が必要でした。Lighthouseだけで終わらせず、低速モバイルのウォーターフォールと実ページの目視確認を合わせるのが一番確実でした。
Claude Codeの導入をチームで進めるなら、フォント最適化もCLAUDE.mdにルール化しておくと再発を防ぎやすくなります。まずは無料チートシートで日常コマンドと安全な依頼の型を確認し、継続的に使う場合は商品一覧のテンプレートや教材を手元に置くと、レビュー時間を減らせます。サイト全体のCore Web Vitals改善、記事品質ルール、収益CTAまでまとめて整えたい場合はClaude Code研修・導入相談を検討してください。
公開前のセルフチェックです。タイトルとdescriptionは検索意図に合っています。本文はフォント戦略、実装、検証、失敗例まで含めています。実例はブログ、SaaS、LP、アイコンフォントの4つです。コード例はAstro、CSS、bash、Lighthouse確認を入れました。外部リンクはMDNとweb.devの公式資料、内部リンクは関連するClaudeCodeLab記事とCTAを入れています。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Code Permission Receipt Pattern: 許可、証拠、ロールバックを残す運用
Claude Codeの権限運用を安全にする permission receipt。許可範囲、承認待ち、検証コマンド、CTA導線を記録します。
Claude CodeとCodex、結局どっち?事故らない“併用”の現実解
OpenAIのCodexとClaude Code、どっちが得意でどっちに任せる?両方を安全に併用する作業分担と権限・検証のワークフローを、僕の失敗談つきで解説します。
Claude Codeサブエージェント実装ガイド: 記事・コード作業を安全に並列委譲する方法
Claude Codeサブエージェントで記事・コード作業を安全に並列化する実装ガイド。委譲基準、プロンプト、失敗例を解説。