既存プロジェクトとデザインシステムを統一するため、内部開発のアプリのフォントをInterからNoto Sans JPに変更する必要がありました。
最初はGoogle Fonts CDN方式を使用していましたが、実装を進める中で2つの課題が浮かび上がりました。
1つ目は、**CSP(Content Security Policy)の設定が複雑化**していたこと。外部フォントサービスのドメインを許可リストに追加する必要があり、セキュリティ設定の管理が煩雑でした。
2つ目は、**外部サービスへの依存**です。Google Fontsがダウンのときにフォントが読み込めないリスクや、通信遅延がページロード時間に影響を与える懸念がありました。
そこで、Next.jsの
## こんな人におすすめ
この記事は以下のような方に役立ちます。
- 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の
- CSP(Content Security Policy)の最適化
## 実装方針
1.
2. フォント設定オブジェクトを作成(weights, display, variable)
3.
4.
5.
6.
## ポイント
### next/fontの設定
``
4. CSPの簡素化によるセキュリティ向上
**得られる効果:**
- パフォーマンスの向上(FCP改善、外部通信削減)
- セキュリティの強化(外部依存の排除)
- 開発効率の向上(設定の一元化)
この手法は、日本語フォントを使用するNext.jsプロジェクトであればほぼそのまま適用できる汎用的なソリューションです。プロジェクトの要件に合わせて、ぜひ試してみてください。
## 参考リンク
- [Next.js Font Optimization Documentation](https://nextjs.org/docs/app/building-your-application/optimizing/fonts)
- [Google Fonts Noto Sans JP](https://fonts.google.com/noto/specimen/Noto+Sans+JP)
- [Tailwind CSS v4 Documentation](https://tailwindcss.com/docs/v4)
- [Web Font Loading Best Practices](https://web.dev/font-loading/)
最初は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)の最適化
## 実装方針
1.
next/font/googleからNoto Sans JPをインポート2. フォント設定オブジェクトを作成(weights, display, variable)
3.
<html>要素にCSS変数を適用4.
<body>要素にfont-sansクラスを追加5.
globals.cssからCDN importを削除し、@themeブロックを更新6.
next.config.tsのCSPから外部フォントドメインを削除## ポイント
### next/fontの設定
``
tsx
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}>
`
### Tailwind CSS v4との統合
`css
@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 との統合がシームレスで、デザインシステムの保守性が向上しました
## トラブルシューティング
### フォントが正しく読み込まれない
**現象:** ビルド後にフォントが適用されず、フォールバックフォントが表示される
**原因と解決策:**
1. **subsetsの指定ミス**
`javascript
// ❌ 誤った指定
subsets: ['japanese'] // この指定は不要
// ✅ 正しい指定
subsets: ['latin'] // 日本語は自動で含まれる
`
2. **環境変数の未設定**
`bash
# 環境変数が正しく設定されているか確認
echo $NODE_ENV # production であることを確認
# 開発環境ではnext devで確認
npm run dev
`
3. **キャッシュの問題**
`bash
# Next.jsキャッシュをクリア
rm -rf .next
npm run build
`
### CSS変数が適用されない
**現象:** Tailwind CSSのfont-sansが適用されない
**解決策:**
1. **html要素のクラス確認**
`html
<!-- html要素にfontクラスが適用されているか確認 -->
<html lang="ja" class="font-sans">
`
2. **globals.cssの@themeブロック確認**
`css
@theme {
--font-sans: var(--font-noto-sans-jp), -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, sans-serif;
}
`
### ビルドサイズが大きくなる
**現象:** フォントファイルのためにビルドサイズが増加する
**解決策:**
1. **必要なweightのみを指定**
`javascript
const notoSansJP = Noto_Sans_JP({
weight: ['400', '500', '700'], // 実際に使用するweightのみ
// ...
});
`
2. **preloadの無効化(必要に応じて)**
`javascript
const notoSansJP = Noto_Sans_JP({
display: 'swap',
variable: '--font-noto-sans-jp',
preload: false, // 明示的にpreloadを無効化
});
`
### FOUT(Flash of Unstyled Text)が発生する
**現象:** フォント読み込み中に一時的にフォールバックフォントが表示される
**解決策:**
1. **displayオプションの確認**
`javascript
const notoSansJP = Noto_Sans_JP({
display: 'swap', // FOUTを許容して読み込み速度を優先
// display: 'block' // 完全な読み込みを待つ場合(遅延が発生)
});
`
2. **font-display CSSの確認**
カスタム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:** はい、複数のフォントを同時に使用できます。例えば:
`typescript
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)でも使用できます。設定方法は基本的に同じですが、フォントファイルの最適化がさらに強化されています。
### Q7. フォントのライセンスはどうなっていますか?
**A:** Noto FontsはApache License 2.0で提供されており、商用利用も可能です。詳細は[Google FontsのNoto Sans JPページ](https://fonts.google.com/noto/specimen/Noto+Sans+JP)で確認してください。
### Q8. セルフホスティングのデメリットはありますか?
**A:** 主なデメリットは以下の通りです:
- **ビルドサイズの増加**: フォントファイルがバンドルされる
- **バージョン管理**: フォントの更新時に手動で対応が必要
- **CDNとのトレードオフ**: キャッシュ戦略を考慮する必要がある
## まとめ
Next.jsのnext/fontを使ったNoto Sans JPのセルフホスティングは、シンプルな設定でパフォーマンスとセキュリティの両面で大きなメリットをもたらします。
**実装のポイント:**
1. subsets: ['latin']で最小限のプリロード
2. CSS変数を使った柔軟なフォント管理
3. Tailwind CSS v4の@theme`ブロックとの統合4. CSPの簡素化によるセキュリティ向上
**得られる効果:**
- パフォーマンスの向上(FCP改善、外部通信削減)
- セキュリティの強化(外部依存の排除)
- 開発効率の向上(設定の一元化)
この手法は、日本語フォントを使用するNext.jsプロジェクトであればほぼそのまま適用できる汎用的なソリューションです。プロジェクトの要件に合わせて、ぜひ試してみてください。
## 参考リンク
- [Next.js Font Optimization Documentation](https://nextjs.org/docs/app/building-your-application/optimizing/fonts)
- [Google Fonts Noto Sans JP](https://fonts.google.com/noto/specimen/Noto+Sans+JP)
- [Tailwind CSS v4 Documentation](https://tailwindcss.com/docs/v4)
- [Web Font Loading Best Practices](https://web.dev/font-loading/)


