字体优化
本教程共 42 篇 · 第 18 篇 · 更新于 2026-07-30 · 约 7 分钟阅读
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-sans 和 font-mono 工具类。
预加载行为
字体文件的预加载与字体定义的位置直接相关:
- 在页面中定义:仅在该页面的路由上预加载
- 在布局中定义:在该布局包裹的所有路由上预加载
- 在根布局中定义:在所有路由上预加载
因此,全站使用的字体应放在根布局中。
常用配置选项
| 选项 | 说明 | 默认值 |
|---|---|---|
subsets | 需要预加载的字符子集,如 ['latin'] | - |
weight | 字重,可变字体不需要指定 | 非可变字体必填 |
style | 字体样式 'normal' 或 'italic' | 'normal' |
display | font-display 值:'auto'、'block'、'swap'、'fallback'、'optional' | 'swap' |
preload | 是否预加载 | true |
fallback | 自定义 fallback 字体数组 | - |
adjustFontFallback | 是否自动添加 fallback 字体减少布局偏移 | true |
variable | CSS 变量名 | - |
小结
next/font 是 Next.js 提供的零配置字体优化方案。核心要点:
- Google 字体:从
next/font/google导入,构建时自动下载并自托管 - 本地字体:从
next/font/local导入,src指向字体文件路径 - 消除布局偏移:自动匹配字体度量,无需手动调整
- 推荐使用可变字体:单个文件包含所有字重,体积更小
- CSS 变量方式最适合与 Tailwind CSS 集成