Next.js中字体加载闪烁问题怎么解决?
我在Next.js项目里用Tailwind CSS的Inter字体,但页面加载时总会出现字体闪烁。尝试过在_document.js里用标签引入fonts.googleapis.com,也加了font-display: swap,但问题还是存在。
代码是这样的:
// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html>
<Head>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet" />
</Head>
<Main />
<NextScript />
</Html>
)
}
控制台没报错,但页面加载时字体还是会先显示系统默认字体再切换。有没有更好的优化方法?是不是应该用next/font的方式处理?
你现在的方式是通过动态加载CSS,然后CSS再去拉字体文件。这个过程至少有两轮网络请求(先下CSS,再下woff/woff2),页面渲染时浏览器只能先用系统默认字体占位,等字体下载完再换,这就导致了FOIT(Flash of Invisible Text)或FOUT(Flash of Unstyled Text)——也就是你说的“闪烁”。
真正靠谱的解法只有一个:换成 next/font。这不是建议,这是官方推的方案,而且能从根源上解决这个问题。
下面是具体怎么做:
第一步,把 _pages/_document.js_ 里的Google Fonts外链干掉,一个不留
注意,这里不需要再写任何link标签了。Head留空就行,后面交给next/font处理。
第二步,安装@next/font(如果你还没装的话)
npm install @next/font第三步,在_app.js或者你需要用字体的地方引入Inter
比如在
pages/_app.js里:解释一下关键点:
-
@next/font/google会自动预加载(preload)对应的woff2字体文件- 它不是靠发请求去Google服务器拿CSS,而是在构建时就分析出要用哪些字重(400,500,700),然后生成base64内联或者静态资源链接
- 自动添加
rel="preload"到关键字体资源,让浏览器提前下载- 支持
display: 'swap',确保文本始终可见,不会出现空白期- 更重要的是,它能把字体文件走你的CDN,而不是依赖gstatic.com,减少第三方依赖风险
第四步,更新Tailwind配置(可选但推荐)
虽然Inter现在挂到了全局CSS变量上,但为了统一管理,最好也在tailwind.config.js里声明一下:
这样你在用
font-sans的时候,实际就会用到你配置的Inter字体,而且带变量控制。为什么这样就能解决闪烁?
因为 next/font 做了几件事:
1. 构建时确定字体需求,避免运行时才知道要加载哪个文件
2. 自动生成 preload link 标签插入到,优先级高,提前触发下载
3. 使用 font-face + local fallback 策略,尽可能利用缓存
4. 强制启用 font-display: swap,保证内容不卡住
5. 字体资源托管在自己的域名下,不受跨域和GFW影响(国内访问Google Fonts经常慢)
补充一点:如果你想进一步优化,还可以配合
Content-Security-Policy或者preconnect给字体CDN提速,但在大多数场景下,用了next/font之后,首屏字体加载基本就稳了。最后提醒一句:别再手写link引入Google Fonts了,尤其在生产环境。那玩意儿看着简单,实则坑多,性能不可控,还容易被墙。next/font才是正道。
你现在重新跑一遍项目,应该就不会看到字体闪了。要是还有,检查是不是其他地方还在引用别的字体,或者浏览器强缓存没清干净。