コンパイラかく語りき

import { Fun } from 'programming'

Next.js v13 で導入された @next/font を使って、ウェブフォント読み込みを最適化する

概要

Next.js v13 がリリースされました。

nextjs.org

主な変更点の1つが @next/font の追加。@next/font には以下のような特徴があります。

  • Automatically optimizes your fonts, including custom fonts(カスタムフォントを含めたフォントの最適化)
  • Removes external network requests for improved privacy and performance(フォント読込のための外部リクエストをしない)
  • Built-in automatic self-hosting for any font file(フォントファイルをセルフホストしてくれる)
  • Zero layout shift automatically using the CSS size-adjust property(CSS size-adjust を利用してレイアウトシフトをゼロに)

ただしまだベータ版機能のようですが。

利用方法は全て以下のページに書かれているのですが、自分でも利用してみたので記録を書いていきます。

nextjs.org

セットアップ

パッケージを新規インストール。

npm install @next/font

Google フォントの場合は @next/font/google が利用可能です。今回は Oswald フォントが利用したかったので、以下の1文を追加。

import { Oswald } from '@next/font/google'

次に、設定事項を記載。

const oswald = Oswald({
  variable: '--font-oswald',
  subsets: ['latin'],
})

CSS custom properties を利用しており、font-family: var('--font-oswald'); のようにフォントを適用したいため、 variable を設定しました。ここで CSS custom properties の名称を設定できます。

さらに、subsets も指定。デフォルトでは preload が true となっており、その場合は subsets 指定が必須です。指定が無いと以下のような警告が出ます。

warn  - The @next/font/google font Oswald has no selected subsets. Please specify subsets in the function call or in your next.config.js, otherwise no fonts will be preloaded. Read more: https://nextjs.org/docs/messages/google-fonts-missing-subsets

Oswald フォントには、キリル文字ラテン文字ベトナム文字のサブセットがあるようでしたが、ラテン文字のみ必要だったので、 subsets: ['latin'] を指定しました。

すべての設定項目はこちらに。

nextjs.org

ちなみに、型定義がしっかりしており、Oswald の場合は以下のような感じ。何が指定可能なのか、分かりやすい。

export declare function Oswald(options?: {
    weight?: '200' | '300' | '400' | '500' | '600' | '700' | 'variable' | Array<'200' | '300' | '400' | '500' | '600' | '700'>;
    style?: 'normal' | Array<'normal'>;
    display?: Display;
    variable?: CssVariable;
    preload?: boolean;
    fallback?: string[];
    adjustFontFallback?: boolean;
    subsets?: Array<'cyrillic' | 'cyrillic-ext' | 'latin' | 'latin-ext' | 'vietnamese'>;
}): FontModule;

そして、設定済みのフォントを適用。サイト全体に適用したいので、 app.tsx で適用しました。

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <main className={oswald.variable}>
      <Component {...pageProps} />
    </main>
  )
}

これで、サイト全体で font-family: var('--font-oswald'); が指定可能となりました。(1枚噛ませる DOM が増えるのはちょっと微妙な気がしますが…

挙動を確認してみると、確かに外部(https://fonts.gstatic.com)へのリクエストがなくなり、セルフホストしたフォントを読み込んでいる。フォント読込&適用に伴うレイアウトシフトもしっかり無くなっていました。

Vercel 上でもフォントファイルがデプロイされていることを確認できました。

その他、自前のフォントを使う方法、CSS custom properties ではない方法については、公式ページをご覧ください。

nextjs.org