Development

next/fontに頼りすぎてパフォーマンスが悪化した話

こんにちは。

節約が趣味だったのですが、最近Claude Codeに課金してしまいその凄さに圧倒されています….
フロントエンドチームのKTです。

AIで0から開発をすると、Next.js を提案されることが多いのではないでしょうか。
今回はそのNext.jsの話です。
※Next.jsの批判記事ではありません!

font-familyについて

フロントエンドの開発をしていると色々な諸問題がありますが、その一つがfont-familyだと考えます。

理由は、デバイスによってシステムフォントが異なるため、ユーザーに表示させたいデザインにブレが生じてしまうからです。

そこで、Webフォントという手段があります。

Webフォントは、OSにインストールされているシステムフォントとは異なり、Web上からフォントファイルを読み込んで表示する仕組みです。

代表的なものとしてGoogle FontsやAdobe Fontsなどがあります。

ここで問題となるのは、外部サーバーから配信されるフォントを読み込むため、通信が発生する点です。
このため、ページの初回表示が遅くなったり、フォントの表示にタイムラグが生じる可能性があります。また、ユーザーのIPアドレスが外部に送信されてしまうため、プライバシー面でも注意する必要があるようです。

そのためフロントエンドのパフォーマンスチューニングでは、フォントはよく問題になる要素の一つです。

next/fontについて

Next.js(v13以降)では next/font という機能が提供されています。

これは Google Fonts などのフォントをビルド時にダウンロードし、アプリケーション内で自己ホスティングする仕組みです。

これにより

  • 外部CDNへのリクエストが不要
  • フォントの読み込み最適化
  • プライバシーの向上:ユーザーのIPアドレスが外部(Google等)に送信されないため

などが行われます。

これによりフォントのパフォーマンスは改善すると思います。

実務でのこと

先日、実務でNext.jsとWordPressのJamstack構成の公式サイトのリニューアルプロジェクトがありました。

そこではかなり多くのWebフォントが採用されていましたが、next/fontを使えば問題ないだろうと思っていました。

ところが……

Page Speed Insightについて

突然話は変わりますが、Page Speed Insight(以下、PSI)はご存知でしょうか。

Webページのパフォーマンスをスコア化して評価するツールですが、担当しているサイトのスコアが低いと、ヒヤヒヤしてしまいます。

PSIのスコアは 90点以上が「良好(緑)」、50〜89点が「改善が必要(オレンジ)」、50点未満が「不良(赤)」と色分けされています。

Jamstack構成では、Next.js、Astro、Nuxtなどのフレームワークが採用されることが多いと思います。
これらを使って公式ドキュメントに沿った実装をすれば、パフォーマンスに関しては高得点以外考えられないといったスタンスでいたのですが、

いざほとんど完成した段階で、読み込ませてみると、

50点未満の赤色スコアが表示されたその瞬間は、見て見ぬふりをしたくなりました。
(この時はまだフォントが犯人だとは思ってもいませんでした。)

調査

この状況を打破するために、まず何が原因なのかを調査しました。

まず読み込んでいるフォント(合計4つ)を全て排除しました。

その結果、アニメーションやライブラリを一切使っていないページでも、スコアに53点の差が確認できました。

単純計算、1つのフォントあたり10点近くスコアを落としている可能性があるということです。
(厳密には日本語フォントを含んでいるものの比重が多くなるので一概には言えませんが)

対策

デザインを変えずに対策する方法としては主に以下の方法があると考えます。

余計なfont-weightを指定しない
サイト内で使用していないfont-weightを読み込ませるのは無駄にファイルサイズを大きくしてしまうため見直しました。
可変フォントの場合は、複数のfont-weight用フォントファイルを読み込む必要がないため、フォント数を減らすことができます。

subsets設定
next/fontでは subsets プロパティを指定することで、必要な文字セットのみを読み込むことができます。例えば、英語や数字のみに使用するフォントの場合、latinなどのsubsetsを指定することで不要な文字データを読み込まずに済みます。
これによりフォントファイルのサイズを削減でき、読み込みパフォーマンスの改善につながります。
ただし、日本語フォントでは japanese のサブセット指定に対応していないフォントも多く、その場合は後述の preload: false;で対処するのが良さそうです。

●preload: false
next/font では preload: true がデフォルトで設定されています。通常は重要なフォントを優先的に読み込むためパフォーマンス改善につながります。
しかし、日本語フォントはファイルサイズが非常に大きいため、preloadによって他のリソース読み込みを阻害する場合があります。
実際に上述したサイトでは日本語フォントを preload: false にすることでスコアが若干改善しました。

しかし、実際に試してみたところ、上記の3つの方法を全て徹底しても10点上がれば良い方かなと感じました………..

やはり、パフォーマンスを重視するのであればWebフォントの数は最小限に抑える(多くても2つまで)にするのが得策なのではないかと感じました。

日本語の宿命

そもそも日本語フォントは、英数字フォントと比べて文字数が圧倒的に多いという特徴があります。

英数字だけであれば数十文字ですが、日本語では

  • ひらがな
  • カタカナ
  • 漢字

を含むため、フォントファイルが非常に大きくなります。

そのため、日本語サイトでWebフォントを使用する場合、パフォーマンスとデザインのトレードオフになりやすいと言えます。

余談になりますが、Google Fontsの日本語系のフォントで代表的なNoto Sans JPですが、2025年4月のWindows Updateにて標準搭載されたようです(Noto Serif JPも)。

そのため、Noto系のフォントを使用する場合はローカルのNotoフォントを読み込むようにすると、スコア改善には役立ちそうもないですが、個々のUX向上という意味ではよろしいかもしれません。
参考リンク

  /* ローカルフォントを有線 */
  @font-face {
    font-family: 'Local Noto Sans JP';
    src: 
      local('Noto Sans JP'), /* Windows用 */
      local('Noto Sans CJK JP Regular') /* Android用 */;
  }

  body {
    font-family: "Local Noto Sans JP", "Noto Sans JP", sans-serif;
  }

ちなみにApple系のOSでNoto Sans JPを使いたい場合はWebフォントに頼るしかないようです….

作業を通して思ったこと

今回の作業を通して思ったことは、パフォーマンスを高めること自体が目的ではなく、それによって得られる結果やゴールに着目する必要があるということです。

私自身が普段、目の前のタスクやソースコードにばかり注視しがちですが、実際は俯瞰した視点で物事をみるのが大事であると改めて感じました。

まとめ

今回の検証を通して、next/fontを使用していても、Webフォントの数が増えるとパフォーマンスに大きく影響することを実感しました。特に日本語フォントはファイルサイズが大きいため、フォントの数や読み込み方法はしっかり考える必要があります。

今回記載したように、

  • 不要なfont-weightを読み込まない
  • subsetsを適切に設定する
  • 日本語フォントのpreloadは慎重に検討する

といった対応だけでも多少の改善は見込めます。
とはいえ一番効果的なのは「Webフォントを増やしすぎないこと」だと思いました。

デザインとの兼ね合いもあるため一概には言えませんが、最終的には「そのサイトで何を達成したいのか」という目的に立ち返り、デザイン・パフォーマンス・開発コストのバランスを考えることが重要だと感じました。

おすすめ記事

Recommend