跳到主要内容

Font Module

next/font 会自动优化你的字体(包括自定义字体),并移除外部网络请求,从而提升隐私和性能。

它为任意字体文件提供内置自动自托管。这意味着你可以无布局偏移地(layout shift)最佳加载 Web 字体。

你还可以便捷地使用所有 Google Fonts。CSS 和字体文件会在构建时下载,并与其他静态资源一起自托管。浏览器不会向 Google 发送任何请求。

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

// 加载可变字体时,无需指定 font weight
const inter = Inter({
subsets: ['latin'],
display: 'swap',
})

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

要在所有页面中使用字体,请将其添加到 /pages 下的 _app.js 文件

pages/_app.js
import { Inter } from 'next/font/google'

// 加载可变字体时,无需指定 font weight
const inter = Inter({ subsets: ['latin'] })

export default function MyApp({ Component, pageProps }) {
return (
<main className={inter.className}>
<Component {...pageProps} />
</main>
)
}

🎥 视频讲解: 了解更多关于 next/font 的用法 → YouTube(6 分钟)

参考

font/googlefont/local类型是否必填
src字符串或对象数组
weight字符串或数组必填/可选
style字符串或数组-
subsets字符串数组-
axes字符串数组-
display字符串-
preload布尔值-
fallback字符串数组-
adjustFontFallback布尔值或字符串-
variable字符串-
declarations对象数组-

src

字体文件的路径,可以是字符串或对象数组(类型为 Array<{path: string, weight?: string, style?: string}>),相对于调用字体加载函数的目录。

用于 next/font/local

  • 必填

示例:

  • src:'./fonts/my-font.woff2',其中 my-font.woff2 位于 app/fonts 目录下
  • src:[{path: './inter/Inter-Thin.ttf', weight: '100',},{path: './inter/Inter-Regular.ttf',weight: '400',},{path: './inter/Inter-Bold-Italic.ttf', weight: '700',style: 'italic',},]
  • 如果在 app/page.tsx 中调用字体加载函数,使用 src:'../styles/fonts/my-font.ttf',则 my-font.ttf 位于项目根目录下的 styles/fonts

weight

字体 weight 可选值如下:

  • 单个权重字符串,或可变字体的权重范围字符串
  • 非可变字体可用权重数组,仅适用于 next/font/google

用于 next/font/googlenext/font/local

示例:

  • weight: '400':单个权重字符串——如 Inter 可选 '100''200''300''400''500''600''700''800''900''variable'(默认)
  • weight: '100 900':可变字体的权重范围
  • weight: ['100','400','900']:非可变字体的权重数组

style

字体 style 可选值如下:

  • 字符串值,默认 'normal'
  • 非可变 Google 字体可用样式数组,仅适用于 next/font/google

用于 next/font/googlenext/font/local

  • 可选

示例:

  • style: 'italic':字符串,可为 normalitalicnext/font/google
  • style: 'oblique':字符串,可为任意标准字体样式(next/font/local
  • style: ['italic','normal']:Google 字体的样式数组

subsets

字体 subsets 由字符串数组定义,指定你希望预加载的子集。指定的子集会在 preload 为 true 时自动注入 preload 标签(默认)。

用于 next/font/google

  • 可选

示例:

  • subsets: ['latin']:包含 latin 子集的数组

所有可用子集可在 Google Fonts 页面查看。

axes

部分可变字体有额外的 axes 可选。默认只包含字体权重以减小文件体积。可选值取决于具体字体。

用于 next/font/google

  • 可选

示例:

display

字体 display 可选值为 'auto''block''swap''fallback''optional',默认 'swap'

用于 next/font/googlenext/font/local

  • 可选

示例:

  • display: 'optional':设置为 optional

preload

布尔值,指定是否预加载字体。默认 true

用于 next/font/googlenext/font/local

  • 可选

示例:

  • preload: false

fallback

字体加载失败时的备用字体。为字符串数组,无默认值。

  • 可选

用于 next/font/googlenext/font/local

示例:

  • fallback: ['system-ui', 'arial']:设置备用字体为 system-uiarial

adjustFontFallback

  • 对于 next/font/google:布尔值,指定是否自动使用备用字体以减少布局偏移。默认 true
  • 对于 next/font/local:字符串或布尔值 false,可选 'Arial''Times New Roman'false,默认 'Arial'

用于 next/font/googlenext/font/local

  • 可选

示例:

  • adjustFontFallback: falsenext/font/google
  • adjustFontFallback: 'Times New Roman'next/font/local

variable

字符串,用于定义 CSS 变量名(CSS 变量用法)。

用于 next/font/googlenext/font/local

  • 可选

示例:

  • variable: '--my-font':声明 CSS 变量 --my-font

declarations

字体 face 描述符 的键值对数组,用于进一步定义生成的 @font-face

用于 next/font/local

  • 可选

示例:

  • declarations: [{ prop: 'ascent-override', value: '90%' }]

示例

Google Fonts

要使用 Google 字体,从 next/font/google 以函数方式导入。推荐使用可变字体以获得最佳性能和灵活性。

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

// 加载可变字体时,无需指定 font weight
const inter = Inter({
subsets: ['latin'],
display: 'swap',
})

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

如果无法使用可变字体,必须指定权重

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

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

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

要在所有页面中使用字体,请将其添加到 /pages 下的 _app.js 文件

pages/_app.js
import { Inter } from 'next/font/google'

// 加载可变字体时,无需指定 font weight
const inter = Inter({ subsets: ['latin'] })

export default function MyApp({ Component, pageProps }) {
return (
<main className={inter.className}>
<Component {...pageProps} />
</main>
)
}

如果无法使用可变字体,必须指定权重

pages/_app.js
import { Roboto } from 'next/font/google'

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

export default function MyApp({ Component, pageProps }) {
return (
<main className={roboto.className}>
<Component {...pageProps} />
</main>
)
}

你可以通过数组指定多个权重和/或样式:

app/layout.js
const roboto = Roboto({
weight: ['400', '700'],
style: ['normal', 'italic'],
subsets: ['latin'],
display: 'swap',
})

提示: 多单词字体名请用下划线(_)连接。例如 Roboto Mono 应导入为 Roboto_Mono

<head> 中应用字体

你也可以不使用 wrapper 和 className,而是在 <head> 中注入样式:

pages/_app.js
import { Inter } from 'next/font/google'

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

export default function MyApp({ Component, pageProps }) {
return (
<>
<style jsx global>{`
html {
font-family: ${inter.style.fontFamily};
}
`}</style>
<Component {...pageProps} />
</>
)
}

单页面使用

要在单个页面中使用字体,直接在该页面引入:

pages/index.js
import { Inter } from 'next/font/google'

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

export default function Home() {
return (
<div className={inter.className}>
<p>Hello World</p>
</div>
)
}

指定子集

Google Fonts 会自动子集化,以减小字体文件体积并提升性能。你需要定义要预加载的子集。如果 preloadtrue 却未指定子集,会收到警告。

只需在函数调用时添加:

app/layout.tsx
const inter = Inter({ subsets: ['latin'] })
pages/_app.js
const inter = Inter({ subsets: ['latin'] })

详见 Font API 参考

多字体使用

你可以在应用中导入并使用多个字体。有两种方式:

第一种方式是创建一个工具函数导出字体,并在需要的地方导入并应用其 className。这样只有在渲染时才会预加载字体:

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 }: { children: React.ReactNode }) {
return (
<html lang="en" className={inter.className}>
<body>
<div>{children}</div>
</body>
</html>
)
}
app/page.tsx
import { roboto_mono } from './fonts'

export default function Page() {
return (
<>
<h1 className={roboto_mono.className}>My page</h1>
</>
)
}

如上,Inter 会全局应用,Roboto Mono 可按需导入应用。

另一种方式是创建 CSS 变量,结合你喜欢的 CSS 方案使用:

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

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

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

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={`${inter.variable} ${roboto_mono.variable}`}>
<body>
<h1>My App</h1>
<div>{children}</div>
</body>
</html>
)
}
app/global.css
html {
font-family: var(--font-inter);
}

h1 {
font-family: var(--font-roboto-mono);
}

如上,Inter 全局应用,<h1> 标签使用 Roboto Mono

建议: 多字体请谨慎使用,每增加一种字体,客户端都需额外下载资源。

本地字体

导入 next/font/local 并指定本地字体文件的 src。推荐使用可变字体以获得最佳性能和灵活性。

app/layout.tsx
import localFont from 'next/font/local'

// 字体文件可与 `app` 目录同级
const myFont = localFont({
src: './my-font.woff2',
display: 'swap',
})

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={myFont.className}>
<body>{children}</body>
</html>
)
}
pages/_app.js
import localFont from 'next/font/local'

// 字体文件可与 `pages` 目录同级
const myFont = localFont({ src: './my-font.woff2' })

export default function MyApp({ Component, pageProps }) {
return (
<main className={myFont.className}>
<Component {...pageProps} />
</main>
)
}

如需为同一字体族使用多个文件,src 可为数组:

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

详见 Font API 参考

配合 Tailwind CSS 使用

next/font 可与 Tailwind CSS 无缝集成,使用 CSS 变量

如下示例,使用 next/font/googleInterRoboto_Mono 字体(你也可以用任意 Google 字体或本地字体)。通过 variable 选项定义 CSS 变量名,然后在 HTML 文档中应用。

提示: 你可以将这些变量加到 <html><body> 标签,具体取决于你的需求和项目风格。

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,
}: {
children: React.ReactNode
}) {
return (
<html
lang="en"
className={`${inter.variable} ${roboto_mono.variable} antialiased`}
>
<body>{children}</body>
</html>
)
}
pages/_app.js
import { Inter } from 'next/font/google'

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

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

export default function MyApp({ Component, pageProps }) {
return (
<main className={`${inter.variable} ${roboto_mono.variable} font-sans`}>
<Component {...pageProps} />
</main>
)
}

最后,在 Tailwind CSS 配置中添加 CSS 变量:

Tailwind CSS v4

Tailwind v4 起,默认无需配置。如需自定义配置,请参考官方文档

global.css
@import 'tailwindcss';

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

Tailwind CSS v3

tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./app/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
fontFamily: {
sans: ['var(--font-inter)'],
mono: ['var(--font-roboto-mono)'],
},
},
},
plugins: [],
}

现在你可以用 font-sansfont-mono 工具类应用字体:

<p class="font-sans ...">The quick brown fox ...</p>
<p class="font-mono ...">The quick brown fox ...</p>

应用样式

你可以通过三种方式应用字体样式:

className

返回只读 CSS className,可传递给 HTML 元素。

<p className={inter.className}>Hello, Next.js!</p>

style

返回只读 CSS style 对象,可传递给 HTML 元素,包括 style.fontFamily 访问字体及备用字体。

<p style={inter.style}>Hello World</p>

CSS 变量

如需在外部样式表中设置样式并指定更多选项,可用 CSS 变量方式。

除了导入字体,还需导入定义 CSS 变量的样式文件,并在字体加载对象中设置 variable 选项:

app/page.tsx
import { Inter } from 'next/font/google'
import styles from '../styles/component.module.css'

const inter = Inter({
variable: '--font-inter',
})

要使用字体,将父容器的 className 设为字体加载器的 variable,文本的 className 设为外部 CSS 文件的样式:

app/page.tsx
<main className={inter.variable}>
<p className={styles.text}>Hello World</p>
</main>

component.module.css 文件中定义 text 选择器:

styles/component.module.css
.text {
font-family: var(--font-inter);
font-weight: 200;
font-style: italic;
}

如上,Hello World 文本使用 Inter 字体及生成的备用字体,权重 200,斜体。

使用字体定义文件

每次调用 localFont 或 Google 字体函数,都会在应用中托管一个字体实例。因此,如需多处使用同一字体,建议集中加载并导出字体对象。

例如,在 app 根目录的 styles 文件夹下创建 fonts.ts 文件:

styles/fonts.ts
import { Inter, Lora, Source_Sans_3 } from 'next/font/google'
import localFont from 'next/font/local'

// 定义可变字体
const inter = Inter()
const lora = Lora()
// 定义非可变字体的两个权重
const sourceCodePro400 = Source_Sans_3({ weight: '400' })
const sourceCodePro700 = Source_Sans_3({ weight: '700' })
// 定义本地自定义字体,GreatVibes-Regular.ttf 存放于 styles 文件夹
const greatVibes = localFont({ src: './GreatVibes-Regular.ttf' })

export { inter, lora, sourceCodePro400, sourceCodePro700, greatVibes }

你可以在代码中这样使用这些定义:

app/page.tsx
import { inter, lora, sourceCodePro700, greatVibes } from '../styles/fonts'

export default function Page() {
return (
<div>
<p className={inter.className}>Hello world using Inter font</p>
<p style={lora.style}>Hello world using Lora font</p>
<p className={sourceCodePro700.className}>
Hello world using Source_Sans_3 font with weight 700
</p>
<p className={greatVibes.className}>My title in Great Vibes font</p>
</div>
)
}

为便于在代码中访问字体定义,可在 tsconfig.jsonjsconfig.json 中定义路径别名:

tsconfig.json
{
"compilerOptions": {
"paths": {
"@/fonts": ["./styles/fonts"]
}
}
}

现在你可以这样导入字体定义:

app/about/page.tsx
import { greatVibes, sourceCodePro400 } from '@/fonts'

预加载

当你在站点页面调用字体函数时,字体不会全局可用并在所有路由预加载,而是根据使用的文件类型,仅在相关路由预加载:

  • 如果是唯一页面,则只在该页面的唯一路由预加载。
  • 如果是 layout,则会在该 layout 包裹的所有路由预加载。
  • 如果是 root layout,则会在所有路由预加载。

当你在站点页面调用字体函数时,字体不会全局可用并在所有路由预加载,而是根据使用的文件类型,仅在相关路由预加载:

  • 如果是唯一页面,则只在该页面的唯一路由预加载
  • 如果在 自定义 App 中,则会在 /pages 下所有路由预加载

版本变更

版本变更内容
v13.2.0@next/font 更名为 next/font,无需单独安装。
v13.0.0@next/font 新增。