Nuxt 3 + Tailwind CSS 客户端导航链接下划线闪烁问题

记录 Nuxt 3 配合 Tailwind CSS 时,客户端导航导致链接文字出现下划线闪烁的问题及解决方案。

NuxtTailwind CSSCSS踩坑
Nuxt 3 + Tailwind CSS 客户端导航链接下划线闪烁问题

问题描述

在 Nuxt 3 项目中使用 Tailwind CSS 时,发现一个奇怪的现象:

  • 首次通过客户端导航(点击 <NuxtLink>)跳转到某个页面时,所有链接文字都会出现下划线
  • 手动刷新页面后,下划线消失,样式恢复正常

这个问题在开发模式和生产构建后都会出现。

原因分析

Tailwind CSS 的 Preflight(基于 modern-normalize)会重置链接样式:

a {
  color: inherit;
  text-decoration: inherit;
}

正常情况下,这会让链接继承父元素的 text-decoration(通常是 none),从而去掉浏览器默认的下划线。

问题出在 Nuxt 的客户端导航机制

  1. 用户点击 <NuxtLink>,Vue Router 拦截导航
  2. 新页面组件异步加载并渲染
  3. 在 CSS 完全加载/应用之前,页面已经渲染了
  4. 此时浏览器使用默认样式(链接带下划线)
  5. CSS 加载完成后,下划线消失

这就是典型的 FOUC(Flash of Unstyled Content) 问题。

为什么刷新就正常了?

刷新页面时,浏览器会等待所有 CSS 加载完成后再渲染页面(SSR 模式下 HTML 和 CSS 是一起返回的)。所以刷新后样式是正确的。

而客户端导航是 JavaScript 驱动的,CSS 的加载和页面的渲染是异步的,就出现了时序差。

解决方案

尝试了多种方案:

  • @layer base 覆盖 — 无效,CSS layers 的优先级问题
  • corePlugins.preflight: false — 无效,且破坏其他基础样式
  • features.inlineStyles: true — 无效
  • 页面过渡动画 — 只是掩盖,不能根治

最终有效的方案是在 app.vue 中用 !important 强制覆盖:

<style>
a:not(.prose a) {
  text-decoration-line: none !important;
}
</style>

关键点:

  • !important 是为了对抗 Tailwind CSS layers 的优先级
  • :not(.prose a) 排除文章正文区域,保留文章内链接的下划线(可读性需要)

总结

这是 Nuxt 3 + Tailwind CSS 的一个已知问题,本质上是 CSS 加载时序导致的 FOUC。!important 虽然不够优雅,但在这个场景下是务实的解决方案。

如果你有更好的方案,欢迎在 Issues 提出!

评论