在Next.js Pages Router中结合Tailwind v4的CSS优先配置正确定义next/font的方法
我之前在Pages Router下用Tailwind v4的CSS优先模式配置next/font时,也踩过一模一样的「--font-inter is not defined」坑,完全懂这种代码逻辑看起来没问题,但控制台报错的烦躁😅。核心问题就是加载顺序搞反了:Tailwind的主题变量在globals.css里先初始化了,但next/font的CSS变量要等到_app.tsx组件渲染才会挂载到DOM上,这时候Tailwind早就完成初始化了,自然找不到变量。
而且官方文档确实有bug,给Pages Router的例子混用了App Router的写法,浪费了我不少时间。下面是我实测可行的解决方法,核心就是让字体变量在Tailwind初始化之前就出现在页面中:
解决思路
要打破这个加载顺序的死循环,我们不能等到_app.tsx渲染组件时才挂载字体变量,而是要把next/font的CSS变量提前到页面的<head>里注入。虽然直接在_document.tsx里用next/font的组件会报错,但我们可以用next/font提供的getVariableCss()方法手动提取变量CSS,然后插入到<head>的内联样式中。
具体步骤
1. 统一管理字体实例(可选但推荐)
先抽离一个单独的文件来定义所有字体实例,避免在多个文件重复写,维护起来更方便,比如创建lib/fonts.ts:
// lib/fonts.ts import { Inter, Inter_Tight, Roboto_Mono } from "next/font/google"; export const inter = Inter({ variable: "--font-inter", subsets: ["latin"], }); export const interTight = Inter_Tight({ variable: "--font-inter-tight", subsets: ["latin"], }); export const robotoMono = Roboto_Mono({ variable: "--font-roboto-mono", subsets: ["latin"], weight: ["400", "700"], });
2. 修改_document.tsx注入字体变量CSS
在pages/_document.tsx中,导入我们的字体实例,用getVariableCss()获取变量的CSS代码,然后作为内联样式插入到<head>里。这样页面加载时,这些字体变量会先于globals.css加载:
// pages/_document.tsx import Document, { Html, Head, Main, NextScript } from "next/document"; import { inter, interTight, robotoMono } from "@/lib/fonts"; export default class MyDocument extends Document { render() { return ( <Html> <Head> {/* 注入字体变量的CSS,确保它在globals.css之前加载 */} <style dangerouslySetInnerHTML={{ __html: ` ${inter.getVariableCss()} ${interTight.getVariableCss()} ${robotoMono.getVariableCss()} `, }} /> </Head> <body> <Main /> <NextScript /> </body> </Html> ); } }
3. 简化_app.tsx的代码
现在字体变量已经在页面初始HTML里存在了,_app.tsx里就不需要再给根容器加那些variable类了,只需要导入全局样式即可:
// pages/_app.tsx import type { AppProps } from "next/app"; import "@/styles/globals.css"; export default function App({ Component, pageProps }: AppProps) { return <Component {...pageProps} />; }
4. 保持globals.css的主题配置不变
你原来写的globals.css主题配置是完全正确的,现在字体变量已经提前加载,不会再出现未定义的错误:
/* src/styles/globals.css */ @import "tailwindcss"; @theme inline { --font-sans: var(--font-inter); --font-narrow: var(--font-inter-tight); --font-mono: var(--font-roboto-mono); }
为什么这个方法有效?
通过在_document.tsx的<head>中插入字体变量的CSS,这些变量会在页面的初始HTML中就存在,当浏览器加载globals.css并执行Tailwind的@theme inline时,就能直接找到--font-inter这些变量,完美避开了加载顺序的问题。
我就是用这个方法解决了自己遇到的同样问题,亲测在Pages Router + Tailwind v4的CSS优先模式下完全可行,也避开了官方文档的错误示例。




