📕

Next.js 13×Tailwind @next/fontでGoogleFontsやローカルフォントを高速化してみる

2023/07/13に公開

Next.js 13備忘録のこれまで

これまでの記事をご参考ください

今後、執筆予定の記事は下記となります。
気になる方は、いいね!押してもらえると、頑張って早めに書いていきますので、どうぞよろしくお願いします🙇‍♂️

  • Server Component使った実装とは 〜Static RenderingとDynamic Rendering〜
  • microCMSを使った検索機能を実装する際に迷ったServer ComponentとClient Componentの使い分け
  • App Router を使った際の多言語サイトの作り方
  • Next.js 13でハマったPDF読み込みの実装方法
  • microCMSのみで実現する、APIキーを隠蔽しつつ、簡易的いいね機能の実装してみる

環境について

Node.js v19.4.0
Next.js 13.4.9
tailwindcss: 3.3.2

@next/font~って何?

公式
https://nextjs.org/docs/app/building-your-application/optimizing/fonts

また、こちらの記事が素晴らしいです!
https://zenn.dev/siino/articles/b42d658af571f0

上記によると、
FontsをセルフホスティングしてNext側で最適化しており、next/font導入後は、GoogleFontsのリクエストはゼロになっております。
また、ローカルフォントのリクエストは発生していますが、リードタイムも若干低くなる傾向にあるみたいですね。(記事では50msぐらい)

Adobe Fontとか使えるの?

残念ながら、@next/fontはまだ Typekit をサポートしていないみたいです。

ただ、Next.jsでTypekitフォントを使用できます。
Next.js 13 より前には、自動フォント最適化と呼ばれる機能があり、現在も存在しており、Typekitをサポートしています。

https://github.com/vercel/next.js/pull/24834

どんな感じで書くの?

defalutで書かれてますね。

src/app/layout.tsx
import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  )
}

variable fontがパフォーマンス面では良いですが、そうでない場合は、下記のようにwidthを指定して書けばよさそうです。

src/app/layout.tsx
import './globals.css'
import { Noto_Sans_JP } from 'next/font/google'

const notojp = Noto_Sans_JP({
  weight: ["400", "500"],
  subsets: ["latin"],
  display: "swap",
});

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={notojp.className}>{children}</body>
    </html>
  )
}

Tailwindで個別に当てたい時は?

CSS Variables使えばいけそうです。

src/app/layout.tsx
import './globals.css'
import { Raleway, Merriweather_Sans } from "@next/font/google";

const raleway = Raleway({
  variable: "--display-font",
});

const merriweather = Merriweather_Sans({
  variable: "--body-font",
});

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={`${raleway.variable} ${merriweather.variable}`}>{children}</body>
    </html>
  )
}

これらの変数をtailwindの設定に使って、フォントファミリーを定義することができます。

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    fontFamily: {
      "display": "var(--display-font)",
      "body": "var(--body-font)",
    },
    extend: {
      backgroundImage: {
        'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
        'gradient-conic':
          'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
      },
    },
  },
  plugins: [],
}

複数フォント(ローカルフォント含)を使いつつ、グローバルに当てたい時は?

フォント定義ファイルの使用すると、いい感じ管理しつつ、CSS Variables使えばいけそうです。
例えば、アプリディレクトリのルートにあるstylesフォルダにfonts.tsファイルを作成します。

src/styles/fonts.ts
import { Noto_Sans_JP } from 'next/font/google'
import localFont from 'next/font/local'

const notojp = Noto_Sans_JP({
  weight: ["400", "500"],
  subsets: ["latin"],
  variable: "--font-notojp",
  display: "swap",
});

// カスタムローカルフォントを定義する
const ttnorms = localFont({
  src: './fonts/TTNorms-Regular.otf',
  variable: "--font-ttnorms",
  display: 'swap',
})
 
export { montserrat, notojp, ttnorms }

上記のファイルをインポートします。

src/app/layout.tsx
import './globals.css'
import { notojp, ttnorms } from '../styles/fonts'

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={`${notojp.variable} ${ttnorms.variable}`}>{children}</body>
    </html>
  )
}

最後に、globals.cssファイルでfont-familyを指定してあげます。

src/app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
  font-family: var(--font-ttnorms), var(--font-notojp), sans-serif;
}

まとめ・振り返り

フォント読み込みが早くなるのは嬉しいですよね。

フォント選びは奥が深く、デザイナーさん基本選んでくれることが多いですが、いろんなブラウザや重さなどを考慮すると、フロントエンドの立場から話せるといいですね。

参考
https://ics.media/entry/200317/

とは言っても、フォントにこだわりがあるのは基本ですし、僕自身フォントの沼にハマってから、看板やアニメのタイトルもフォント意識するようになり、面白いので暇があるとき探ってみるも良さそうです〜

次回は

  • Server Component使った実装とは 〜Static RenderingとDynamic Rendering〜

この辺りについて、執筆予定です。

参考

Components: Font | Next.js
Next13新機能、@next/fontでフォント読み込みを高速化してみた
Next.js 13 - next/font の使い方 | TIPS | chocolat

Discussion