既存プロジェクトとデザインシステムを統一するため、内部開発のアプリのフォントをInterからNoto Sans JPに変更する必要がありました。
最初はGoogle Fonts CDN方式を使用していましたが、実装を進める中で2つの課題が浮かび上がりました。
1つ目は、CSP(Content Security Policy)の設定が複雑化していたこと。外部フォントサービスのドメインを許可リストに追加する必要があり、セキュリティ設定の管理が煩雑でした。
2つ目は、外部サービスへの依存です。Google Fontsがダウンのときにフォントが読み込めないリスクや、通信遅延がページロード時間に影響を与える懸念がありました。
そこで、Next.jsのnext/fontによるセルフホスティング方式に移行しました。実装してみると、これは想像以上にシンプルで、パフォーマンスとセキュリティの両面で大きな改善が実現できました。
こんな人におすすめ
この記事は以下のような方に役立ちます。
- Next.js で日本語フォント(Noto Sans JP)をセットアップしたい方
- Google Fonts CDN への外部依存を減らしたい方
- Tailwind CSS v4 を使用していて、フォント設定を統合したい方
- CSP(Content Security Policy)を厳しく設定している方
- フォント周りのパフォーマンス最適化に関心のある方
要件
- InterフォントをNoto Sans JPに置き換え
- Google Fonts CDNへの外部リクエストを削除
- Tailwind CSS v4の
@themeブロックとの統合 - CSP(Content Security Policy)の最適化
実装方針
next/font/googleからNoto Sans JPをインポート- フォント設定オブジェクトを作成(weights, display, variable)
<html>要素にCSS変数を適用<body>要素にfont-sansクラスを追加globals.cssからCDN importを削除し、@themeブロックを更新next.config.tsのCSPから外部フォントドメインを削除
ポイント
next/fontの設定
import { Noto_Sans_JP } from 'next/font/google';
const notoSansJP = Noto_Sans_JP({
subsets: ['latin'], // 最小限のプリロード(日本語は自動で含まれる)
weight: ['400', '500', '600', '700'],
display: 'swap', // FOUT防止
variable: '--font-noto-sans-jp',
});
// htmlにCSS変数を適用
<html lang="ja" className={notoSansJP.variable}>
Noto Sans JPのような日本語フォントをnext/font/googleで使う場合、subsetsとweightの指定には次のような注意点があります。
subsetsは['latin']のままでよい: Noto Sans JPは日本語グリフを標準で含んでいるため、latinサブセットを指定するだけで日本語文字も自動的に最適化されます。['japanese']という値は存在せず、指定するとビルドエラーになりますweightは実際に使うものだけ絞る: Noto Sans JPはウェイトごとに個別のフォントファイルとして配信されるため、指定したweightの数だけファイルが生成されます。デザインで使うウェイトが3〜4種類程度であれば、それ以上は指定しないほうがビルドサイズを抑えられますvariableはCSSカスタムプロパティ名を自由に決められる:--font-noto-sans-jpのように用途がわかる名前を付けておくと、Tailwind CSSの@themeやグローバルCSSから参照する際に迷いません
layout.tsx全体では、以下のように<html>と<body>両方にクラスを適用する構成が一般的です。
// app/layout.tsx
import { Noto_Sans_JP } from 'next/font/google';
import './globals.css';
const notoSansJP = Noto_Sans_JP({
subsets: ['latin'],
weight: ['400', '500', '600', '700'],
display: 'swap',
variable: '--font-noto-sans-jp',
});
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ja" className={notoSansJP.variable}>
<body className="font-sans">{children}</body>
</html>
);
}
Tailwind CSS v4との統合
@theme {
--font-sans: var(--font-noto-sans-jp), -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, sans-serif;
}
CSPの簡素化
セルフホスティングにより、以下のドメイン許可を削除できた:
https://fonts.googleapis.com(style-src)https://fonts.gstatic.com(font-src)
学び
next/fontはビルド時にフォントをダウンロードし、自動的に最適化・セルフホスティングするsubsets: ['latin']は最小限のプリロード設定。日本語文字はnext/fontが自動的に処理する- CSS変数を使うことで、Tailwind CSSのユーティリティクラスとシームレスに統合できる
- 外部フォントサービスへの依存を削除することで、CSPがシンプルになりセキュリティが向上する
得られた効果
この実装により、以下の改善が実現できました。
即時の効果:
- CSP ルールの削減: Google Fonts に関連する 2 つのドメイン許可を削除できました
https://fonts.googleapis.com(style-src)https://fonts.gstatic.com(font-src)
- セキュリティの強化: 外部サービスへの依存がなくなり、セキュリティポリシーがシンプルになりました
パフォーマンス面での改善:
- First Contentful Paint(FCP)の改善: フォントがビルド時にダウンロードされるため、ページロード時の外部通信が削減されました
- 安定性の向上: Google Fonts サービスの可用性に依存しなくなり、確実にフォントが読み込まれるようになりました
開発効率の向上:
- セルフホスティングにより、フォント設定が一箇所に集約されて管理が楽になりました
- Tailwind CSS との統合がシームレスで、デザインシステムの保守性が向上しました
トラブルシューティング
フォントが正しく読み込まれない
現象: ビルド後にフォントが適用されず、フォールバックフォントが表示される
原因と解決策:
-
subsetsの指定ミス
// ❌ 誤った指定 subsets: ['japanese'] // この指定は不要 // ✅ 正しい指定 subsets: ['latin'] // 日本語は自動で含まれる -
環境変数の未設定
# 環境変数が正しく設定されているか確認 echo $NODE_ENV # production であることを確認 # 開発環境ではnext devで確認 npm run dev -
キャッシュの問題
# Next.jsキャッシュをクリア rm -rf .next npm run build
CSS変数が適用されない
現象: Tailwind CSSのfont-sansが適用されない
解決策:
-
html要素のクラス確認
<!-- html要素にfontクラスが適用されているか確認 --> <html lang="ja" class="font-sans"> -
globals.cssの@themeブロック確認
@theme { --font-sans: var(--font-noto-sans-jp), -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; }
ビルドサイズが大きくなる
現象: フォントファイルのためにビルドサイズが増加する
解決策:
-
必要なweightのみを指定
const notoSansJP = Noto_Sans_JP({ weight: ['400', '500', '700'], // 実際に使用するweightのみ // ... }); -
preloadの無効化(必要に応じて)
const notoSansJP = Noto_Sans_JP({ display: 'swap', variable: '--font-noto-sans-jp', preload: false, // 明示的にpreloadを無効化 });
FOUT(Flash of Unstyled Text)が発生する
現象: フォント読み込み中に一時的にフォールバックフォントが表示される
解決策:
-
displayオプションの確認
const notoSansJP = Noto_Sans_JP({ display: 'swap', // FOUTを許容して読み込み速度を優先 // display: 'block' // 完全な読み込みを待つ場合(遅延が発生) }); -
font-display CSSの確認
カスタムCSSでフォントの表示動作を調整:@font-face { font-family: 'Noto Sans JP'; font-display: swap; }
よくある質問(FAQ)
Q1. Google Fontsとセルフホスティング、どちらを選ぶべきですか?
A: プロジェクトの要件に応じて選択してください:
Google Fontsを選ぶべきケース:
- プロトタイプや開発初期段階
- 多言語対応が必要でフォントファイルサイズが大きい場合
- CDN経由でフォントを配信する利便性を重視する場合
セルフホスティングを選ぶべきケース:
- セキュリティポリシー(CSP)を厳しく設定している場合
- 外部サービスへの依存を排除したい場合
- パフォーマンス最適化を重視する場合
- オフライン環境でのフォント表示が必要な場合
Q2. サブセット(subsets)の指定は必要ですか?
A: 基本的には不要です。subsets: ['latin'] を指定するだけで、next/font が自動的に日本語文字を含めてくれます。日本語のみのプロジェクトでも latin サブセットを指定することがベストプラクティスです。
Q3. フォントファイルのサイズはどのくらいになりますか?
A: フォントのweight(太さ)の数によって異なりますが、一般的に:
- 1つのweight: 約 200-400KB
- 4つのweight(400, 500, 600, 700): 約 1-1.5MB
- すべてのweight: 約 3-4MB
実際のサイズは npm run build 後の .next フォルダ内で確認できます。
Q4. セルフホスティングすると、本当にパフォーマンスが向上しますか?
A: はい、以下の理由でパフォーマンスが向上します:
- First Contentful Paint (FCP) の改善: フォントがビルド時にバンドルされるため、ページロード時の外部リクエストが削減されます
- TTFBの改善: 外部CDNへの接続時間がなくなるため
- キャッシュ効率: ユーザーがサイトを再訪問した際、ブラウザキャッシュからフォントが読み込まれます
ただし、初回ロード時のファイルサイズが増加するため、キャッシュ戦略が重要になります。
Q5. 複数のフォントを同時にセルフホスティングできますか?
A: はい、複数のフォントを同時に使用できます。例えば:
import { Noto_Sans_JP } from 'next/font/google';
import { Noto_Serif_JP } from 'next/font/google';
const notoSansJP = Noto_Sans_JP({ ... });
const notoSerifJP = Noto_Serif_JP({ ... });
// Tailwind CSSでそれぞれのフォントを定義
@theme {
--font-sans: var(--font-noto-sans-jp), sans-serif;
--font-serif: var(--font-noto-serif-jp), serif;
}
Q6. next/fontはNext.js 13以降でも使用できますか?
A: はい、Next.js 13で導入されたApp Router以降、next/fontの基本的な使い方に大きな変更はありません。2026年時点の最新安定版(Next.js 15系)でも、本記事と同じ手順でNoto Sans JPのセルフホスティングが行えます。バージョンアップ時は念のため公式ドキュメントのnext/fontリファレンスで最新のオプション一覧を確認することをおすすめします。
Q7. フォントのライセンスはどうなっていますか?
A: Noto FontsはApache License 2.0で提供されており、商用利用も可能です。詳細はGoogle FontsのNoto Sans JPページで確認してください。
Q8. セルフホスティングのデメリットはありますか?
A: 主なデメリットは以下の通りです:
- ビルドサイズの増加: フォントファイルがバンドルされる
- バージョン管理: フォントの更新時に手動で対応が必要
- CDNとのトレードオフ: キャッシュ戦略を考慮する必要がある
まとめ
Next.jsのnext/fontを使ったNoto Sans JPのセルフホスティングは、シンプルな設定でパフォーマンスとセキュリティの両面で大きなメリットをもたらします。
実装のポイント:
subsets: ['latin']で最小限のプリロード- CSS変数を使った柔軟なフォント管理
- Tailwind CSS v4の
@themeブロックとの統合 - CSPの簡素化によるセキュリティ向上
得られる効果:
- パフォーマンスの向上(FCP改善、外部通信削減)
- セキュリティの強化(外部依存の排除)
- 開発効率の向上(設定の一元化)
この手法は、日本語フォントを使用するNext.jsプロジェクトであればほぼそのまま適用できる汎用的なソリューションです。プロジェクトの要件に合わせて、ぜひ試してみてください。


