首页 / Next.js 16 入门教程 / 字体优化

Next.js 16 入门教程

字体优化

本教程共 42 篇 · 第 18 篇 · 更新于 2026-07-30 · 约 7 分钟阅读

Next.jsNext.js 16 入门教程字体优化next/fontGoogle Fonts可变字体

18. 字体优化

本节目标:理解 next/font 模块如何自动优化字体加载,掌握 Google 字体和本地字体的最佳实践,消除字体加载导致的布局偏移。

为什么需要字体优化

自定义字体会带来两个性能问题:一是需要额外的网络请求下载字体文件(增加加载时间),二是字体加载过程中的布局偏移(CLS)。当字体文件加载完成时,浏览器会用新字体替换临时字体,导致文字尺寸变化,页面内容发生跳动。

Next.js 的 next/font 模块通过自动自托管解决这两个问题:字体文件在构建时下载并打包为静态资源,与你的应用部署在同一个域名下,消除了外部网络请求;同时通过字体度量匹配,自动消除布局偏移。

next/font 的两种用法

next/font 提供两个入口:next/font/google 用于 Google Fonts,next/font/local 用于本地字体文件。

Google 字体

使用 Google Fonts 最简单——直接导入你想要的字体函数,Next.js 会在构建时自动下载字体文件并自托管:

// app/layout.tsx
import { Inter } from 'next/font/google'

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

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

推荐使用可变字体

可变字体(Variable Font)将多个字重、字宽变体合并到单个文件中,文件体积更小、加载更快。Inter、Geist、Roboto Flex 等都支持可变字体。使用可变字体时不需要指定 weight

如果字体不支持可变字体,则必须指定字重:

import { Roboto } from 'next/font/google'

const roboto = Roboto({
  weight: '400',
  subsets: ['latin'],
})

也可以加载多个字重和样式:

const roboto = Roboto({
  weight: ['400', '700'],
  style: ['normal', 'italic'],
  subsets: ['latin'],
})

多单词字体名用下划线

字体名称中包含空格时,导入时使用下划线连接。例如 Roboto Mono 应写为 Roboto_Mono

本地字体

使用 next/font/local 加载项目中的字体文件:

import localFont from 'next/font/local'

const myFont = localFont({
  src: './my-font.woff2',
})

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

字体文件路径相对于调用 localFont 的文件解析。你可以把字体文件放在 app 文件夹内、public 文件夹内,或任何合适的位置。

如果需要为同一个字体家族加载多个文件(不同字重、不同样式),src 可以是一个数组:

const roboto = localFont({
  src: [
    {
      path: './Roboto-Regular.woff2',
      weight: '400',
      style: 'normal',
    },
    {
      path: './Roboto-Bold.woff2',
      weight: '700',
      style: 'normal',
    },
  ],
})

应用字体的三种方式

1. className(最常用)

将字体对象的 className 传递给目标元素:

<p className={inter.className}>使用 Inter 字体的文本</p>

2. style 对象

使用 style 属性,包含 fontFamily 和 fallback 字体:

<p style={inter.style}>使用 Inter 字体的文本</p>

3. CSS 变量

通过 variable 选项定义 CSS 变量,然后在 CSS 中使用:

// app/layout.tsx
const inter = Inter({
  subsets: ['latin'],
  variable: '--font-inter',
  display: 'swap',
})

export default function RootLayout({ children }) {
  return (
    <html lang="zh" className={inter.variable}>
      <body>{children}</body>
    </html>
  )
}
/* globals.css */
body {
  font-family: var(--font-inter);
}

CSS 变量方式特别适合与 Tailwind CSS 配合使用。

使用多个字体

推荐创建一个字体定义文件统一管理:

// app/fonts.ts
import { Inter, Roboto_Mono } from 'next/font/google'

export const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
})

export const roboto_mono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
})

然后在需要的组件中导入使用:

// app/layout.tsx
import { inter } from './fonts'

export default function Layout({ children }) {
  return (
    <html lang="zh" className={inter.className}>
      <body>{children}</body>
    </html>
  )
}
// app/page.tsx
import { roboto_mono } from './fonts'

export default function Page() {
  return <h1 className={roboto_mono.className}>代码风格的标题</h1>
}

字体数量要克制

每增加一个字体文件,客户端就需要多下载一份资源。建议一个项目最多使用 2-3 个字体。

与 Tailwind CSS 集成

next/font 与 Tailwind CSS 通过 CSS 变量无缝集成:

// app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})

const roboto_mono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-roboto-mono',
})

export default function RootLayout({ children }) {
  return (
    <html lang="zh" className={`${inter.variable} ${roboto_mono.variable}`}>
      <body>{children}</body>
    </html>
  )
}

Tailwind CSS v4 配置:

/* globals.css */
@import 'tailwindcss';

@theme inline {
  --font-sans: var(--font-inter);
  --font-mono: var(--font-roboto-mono);
}

Tailwind CSS v3 配置:

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        sans: ['var(--font-inter)'],
        mono: ['var(--font-roboto-mono)'],
      },
    },
  },
}

配置完成后,就可以直接使用 Tailwind 的 font-sansfont-mono 工具类。

预加载行为

字体文件的预加载与字体定义的位置直接相关:

  • 页面中定义:仅在该页面的路由上预加载
  • 布局中定义:在该布局包裹的所有路由上预加载
  • 根布局中定义:在所有路由上预加载

因此,全站使用的字体应放在根布局中。

常用配置选项

选项说明默认值
subsets需要预加载的字符子集,如 ['latin']-
weight字重,可变字体不需要指定非可变字体必填
style字体样式 'normal''italic''normal'
displayfont-display 值:'auto''block''swap''fallback''optional''swap'
preload是否预加载true
fallback自定义 fallback 字体数组-
adjustFontFallback是否自动添加 fallback 字体减少布局偏移true
variableCSS 变量名-

小结

next/font 是 Next.js 提供的零配置字体优化方案。核心要点:

  1. Google 字体:从 next/font/google 导入,构建时自动下载并自托管
  2. 本地字体:从 next/font/local 导入,src 指向字体文件路径
  3. 消除布局偏移:自动匹配字体度量,无需手动调整
  4. 推荐使用可变字体:单个文件包含所有字重,体积更小
  5. CSS 变量方式最适合与 Tailwind CSS 集成