KumiFont

KumiFont Column

font-display: swap と日本語Webフォント表示最適化

日本語Webフォントは重い。読み込み中の「文字が見えない問題」を解決する font-display と subset の実装手法を解説します。

日本語Webフォントが重い理由

日本語Webフォントは、英文フォントとは比較にならないほどファイルサイズが大きくなります。理由は単純で、英文が約100文字で完結するのに対し、日本語は常用漢字だけで2,136文字、ひらがな・カタカナ・記号を加えると6,000〜7,000文字を含む必要があるからです。

Noto Sans JP のRegularウェイト1つだけで、フルセットなら4MB前後。これを何も考えずに読み込むと、ユーザーがページを開いた瞬間に4MBのダウンロードが始まり、回線が遅い環境では数秒間「文字が見えない」状態が続きます。これが日本語Web特有の「FOIT(Flash of Invisible Text)」問題です。

font-display: swap の役割

font-display: swap は、Webフォントの読み込み中の挙動を制御するCSSプロパティです。swap を指定すると、フォントが読み込み中の間は代替フォント(システムフォントなど)で文字を表示し、Webフォントが読み込み完了したタイミングで一気に切り替えます。

実装は @font-face ルールに1行加えるだけです。

@font-face { font-family: 'Noto Sans JP'; src: url(...); font-display: swap; }

Google Fonts経由で読み込む場合は、URLの末尾に &display=swap を付けるだけで適用されます。これだけでFOITが解消され、ユーザーは読み込み中も文字を見ることができるようになります。KumiFontのソースコードでも display=swap が指定されています。

subset化で表示速度をさらに改善

font-display: swap は表示の体感を改善しますが、ダウンロード自体が軽くなるわけではありません。本質的な高速化には subset(文字セットの絞り込み)が必要です。

Google Fontsの日本語フォントは「Dynamic Subsetting」という仕組みを採用しており、ページ内に実際に使われている文字だけを判定して、必要な部分だけを動的に配信してくれます。これによりフルセット4MBが、実際の表示には数百KB〜1MB程度に圧縮されます。

開発者側で何かを設定する必要はなく、link rel="stylesheet" で fonts.googleapis.com から読み込むだけで自動適用されます。自前ホスティングする場合は、サブセット化済みのwoff2ファイルを生成して配信する必要があり、手間が増えます。特別な理由がなければGoogle Fonts経由を選ぶのが現実的です。

preconnect と preload で初動を速く

さらにチューニングしたい場合は、HTMLの<head>に以下を追加すると初動の表示がさらに速くなります。

<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

これでフォント配信サーバーへのDNS解決とTLSハンドシェイクが事前に行われ、CSSがパースされた瞬間にダウンロードが開始されます。

最重要のフォント1つ(例えばトップページのヒーローに使う見出しフォント)については、rel="preload" を使って優先読み込みを指定する手もあります。ただし preload を多用するとリソース競合で逆に遅くなるので、本当に最重要な1つに絞るのがコツです。

font-display: swap、Google Fonts経由のsubset、preconnectの3点セットを実装すれば、日本語Webフォントの体感速度はかなり改善されます。KumiFontで作ったCSSをサイトに組み込む際にも、必ずこの最適化をセットで適用してください。