必须显式配置 darkMode: 'class',否则 dark: 类在编译时被彻底删除;它只能是 tailwind.config.js 顶层字段,仅接受 'class' 或 'media';'class' 支持按钮切换与 localStorage 持久化,'media' 仅响应系统偏好;切换必须作用于 document.documentElement,且初始化脚本需内联于 <head> 并早于 CSS 加载,配合 try/catch 和 localStorage 读取以避免闪白;所有颜色及交互状态均需手动添加 dark: 变体,并统一 CSS 变量命名。

必须显式配置 darkMode: 'class',否则所有 dark: 类在编译时被彻底删除——不是失效,是压根没生成。
tailwind.config.js 里 darkMode 必须写对位置和值
它只能是配置对象的顶层字段,且只接受 'class' 或 'media'。写成 true、'dark'、空字符串、塞进 theme.extend 或插件里,都会让 Tailwind 直接忽略全部 dark: 规则,不报错也不警告。
-
darkMode: 'class'是唯一支持按钮切换 +localStorage持久化的方案 -
darkMode: 'media'只响应系统偏好,document.documentElement.classList.toggle('dark')完全无效 - 改完必须重启开发服务器(如
npm run dev),Tailwind 不热更配置
切换操作必须作用于 document.documentElement
Tailwind 默认只检查 <html> 元素上是否存在 dark 类。加在 <body> 或任意组件 div 上,dark:bg-gray-800 永远不会生效,尤其在 Next.js/Nuxt 等 SSR 框架中会引发 hydration mismatch 和首屏闪白。
- 正确写法:
document.documentElement.classList.toggle('dark') - 错误写法:
document.body.classList.toggle('dark') - 验证是否生效:直接在 HTML 模板中写
<html class="dark">,再测样式
初始化脚本必须内联在 <head> 里,且早于 CSS 加载
“闪白”不是 bug,是执行时机问题:浏览器先按无 dark 类渲染浅色样式,JS 后加类才触发深色,中间有可见延迟。DOMContentLoaded 或外部 JS 文件都太晚。
立即学习“前端免费学习笔记(深入)”;
- 脚本必须是 IIFE,放在
<head><script>...</script></head>内联位置 - 必须包裹
try/catch,服务端渲染时window不存在 - 逻辑要立刻读
localStorage.getItem('theme'),fallback 到window.matchMedia('(prefers-color-scheme: dark)')
每处颜色都需要手动补 dark: 变体
配了 darkMode: 'class' 只是开了门,不是自动变暗。Tailwind 不推导深色适配,text-gray-700 在深色背景下可能依然看不清。
- 必须显式写出
dark:text-gray-300、dark:bg-gray-900等 -
dark:可叠加其他变体,如dark:hover:bg-gray-700,建议放在最前提高可读性 - focus ring、border、placeholder 等交互细节也需单独适配,否则深色下不可见
最容易被忽略的是:变量初始化时机和命名一致性。JS 设置 data-theme="dark" 时若 CSS 还没解析完,浏览器会先按旧变量渲染一帧;混用 --primary 和 --color-primary 会让主题切换失效。内联默认变量 + 统一命名比写十个切换函数更重要。



















