Tailwind v3+ 默认不启用 dark: 变体,必须在 tailwind.config.js 顶层配置 darkMode: 'class';dark 类须加在 上,切换需用 document.documentElement.classList.toggle('dark'),脚本须内联于 立即执行。

darkMode: 'class' 没写在顶层配置里
Tailwind v3+ 默认不启用 dark: 变体,哪怕你写了 dark:bg-gray-800,只要 tailwind.config.js 里没这行:darkMode: 'class',编译结果里就完全不会有对应 CSS 规则——不是失效,是压根没生成。
常见错误包括:
- 把
darkMode写进theme.extend或plugins里(必须是module.exports的直接子字段) - 误写成
darkMode: true、darkMode: 'dark'或darkMode: ''(只接受'class'或'media') - TypeScript 配置中类型导出错误,导致配置未被 Tailwind 读取
dark 类没加到 document.documentElement
Tailwind 只检查 元素是否含 dark 类。加在 或任意 div 上,dark:bg-gray-800 就永远不会匹配。
SSR 框架(如 Next.js)尤其敏感:如果 hydration 时 没 dark 类,但客户端 JS 后续加了,就会触发水合 mismatch,样式错乱或闪白。
正确切换方式只有一种:document.documentElement.classList.toggle('dark')
别用:document.body.classList.toggle('dark')(无效)useState + useEffect 同步类名(状态与 DOM 不一致)
初始化脚本执行太晚,导致“闪白”
浏览器先渲染无 dark 类的浅色样式,JS 后加载才加类——中间有可见延迟。这不是 bug,是执行时机问题。
解决方法只有一条:脚本必须内联在 里,且立即执行:
- 不能挂
DOMContentLoaded或window.onload - 必须是 IIFE 形式:
(function() { /* 读 localStorage / matchMedia,然后操作 document.documentElement */ })() - 必须包
try/catch(服务端渲染时window不存在) - 推荐 fallback 顺序:
localStorage.getItem('theme')→window.matchMedia('(prefers-color-scheme: dark)').matches
CSS 变量方案和 dark: 混用导致覆盖失效
如果你用了 bg-[var(--color-bg)] 却还保留 dark:bg-gray-800,两者会冲突。Tailwind 生成的 .dark .dark\:bg-gray-800 和 bg-[var(--color-bg)] 的特异性不同,后者常被前者覆盖。
更关键的是:dark: 前缀根本不解析 var(),它只响应 html.dark 或媒体查询。所以 dark:bg-[var(--color-bg)] 实际上是无效写法。
若走 CSS 变量路线,必须:
- 把变量声明在
@layer base块里,挂载到:root或[data-theme="dark"] -
data-theme属性也得设在上 - 在
tailwind.config.js的safelist加正则:/^bg-\[.*\]$/,否则 PurgeCSS 会删掉bg-[var(--color-bg)] - 避免混用命名风格,比如同时存在
--primary和--color-primary
最易忽略的其实是变量初始值:JS 切换前,CSS 文件还没加载完,浏览器会按旧变量渲染一帧。所以 里内联默认 :root 值比写十个切换函数更重要。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











