Menu

字体优化

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

🎥 观看: 了解更多关于使用 next/font 的信息 → YouTube (6 分钟)

next/font 包含 内置的自动自托管功能,适用于 任何 字体文件。这意味着你可以以零布局偏移的方式最佳地加载网页字体,这要归功于底层使用的 CSS size-adjust 属性。

这个新的字体系统还允许你方便地使用所有 Google Fonts,同时考虑到性能和隐私。CSS 和字体文件在构建时下载,并与你的其他静态资源一起自托管。浏览器不会向 Google 发送任何请求。

Google Fonts

自动自托管任何 Google Font。字体包含在部署中,并从与你的部署相同的域名提供服务。浏览器不会向 Google 发送任何请求。

首先,从 next/font/google 中将你想使用的字体作为函数导入。我们建议使用 可变字体 以获得最佳的性能和灵活性。

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="en" className={inter.className}>
      <body>{children}</body>
    </html>
  );
}
app/layout.js
import { Inter } from "next/font/google";
 
// 如果加载可变字体,你不需要指定字体粗细
const inter = Inter ({
  subsets: ["latin"],
  display: "swap",
});
 
export default function RootLayout ({ children }) {
  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>
  );
}
app/layout.js
import { Roboto } from "next/font/google";
 
const roboto = Roboto ({
  weight: "400",
  subsets: ["latin"],
  display: "swap",
});
 
export default function RootLayout ({ children }) {
  return (
    <html lang="en" className={roboto.className}>
      <body>{children}</body>
    </html>
  );
}

你可以通过使用数组来指定多个字重和/或样式:

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

值得注意的是:对于由多个单词组成的字体名称,请使用下划线 (_)。例如,Roboto Mono 应该导入为 Roboto_Mono

指定子集

Google Fonts 会自动进行 子集化。这可以减小字体文件的大小并提高性能。你需要定义要预加载的子集。如果在 preloadtrue 时未指定任何子集,将会出现警告。

你可以通过将其添加到函数调用中来实现这一点:

app/layout.tsx
const inter = Inter ({ subsets: ["latin"] });
app/layout.js
const inter = Inter ({ subsets: ["latin"] });

查看 字体 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/fonts.js
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/layout.js
import { inter } from "./fonts";
 
export default function Layout ({ children }) {
  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>
    </>
  );
}
app/page.js
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/layout.js
import { Inter, Roboto_Mono } from "next/font/google";
 
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 }) {
  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>
  );
}
app/layout.js
import localFont from "next/font/local";
 
// 字体文件可以放在 `app` 目录下
const myFont = localFont ({
  src: "./my-font.woff2",
  display: "swap",
});
 
export default function RootLayout ({ children }) {
  return (
    <html lang="en" className={myFont.className}>
      <body>{children}</body>
    </html>
  );
}

如果你想为单个字体家族使用多个文件,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",
    },
  ],
});

查看 字体 API 参考 以获取更多信息。

与 Tailwind CSS 一起使用

next/font 可以通过 CSS 变量Tailwind CSS 一起使用。

在下面的例子中,我们使用 next/font/google 中的 Inter 字体 (你可以使用任何来自 Google 或本地字体的字体)。使用 variable 选项加载你的字体以定义 CSS 变量名称,并将其分配给 inter。然后,使用 inter.variable 将 CSS 变量添加到你的 HTML 文档中。

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}`}>
      <body>{children}</body>
    </html>
  );
}
app/layout.js
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="en" className={`${inter.variable} ${roboto_mono.variable}`}>
      <body>{children}</body>
    </html>
  );
}

最后,将 CSS 变量添加到你的 Tailwind CSS 配置:

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 工具类来将字体应用到你的元素上。

预加载

当在你网站的某个页面上调用字体函数时,它不会全局可用并在所有路由上预加载。相反,字体只会根据使用它的文件类型在相关路由上预加载:

  • 如果是 唯一页面,它会在该页面的唯一路由上预加载。
  • 如果是 布局,它会在该布局包裹的所有路由上预加载。
  • 如果是 根布局,它会在所有路由上预加载。

重复使用字体

每次调用 localFont 或 Google 字体函数时,该字体都会作为一个实例托管在你的应用程序中。因此,如果你在多个文件中加载相同的字体函数,同一字体的多个实例将被托管。在这种情况下,建议执行以下操作:

  • 在一个共享文件中调用字体加载器函数
  • 将其导出为常量
  • 在每个你想使用这种字体的文件中导入该常量

API 参考

了解更多关于 next/font API 的信息。