必须显式配置 darkmode: 'class',否则 dark: 类名编译时被彻底丢弃;切换主题只能操作 document.documentelement,初始化脚本须内联于 head 中并立即执行,且 localstorage 与 dom 状态须同步更新。

必须显式配置 darkMode: 'class',否则所有 dark: 类名在编译时被彻底丢弃,连警告都没有。
tailwind.config.js 里漏写 darkMode 字段就等于没开暗黑模式
Tailwind v3+ 不再默认启用 dark: 变体。哪怕你写了 dark:bg-slate-800,只要 tailwind.config.js 里没这一行:
darkMode: 'class'
那它就完全不会出现在最终 CSS 中——不是失效,是压根没生成。常见错误包括:
- 误写成
darkMode: true或darkMode: 'dark'(非法值) - 把
darkMode放在theme.extend里(必须是顶层字段) - 用 TypeScript 配置但类型没导出正确,导致配置未被读取
document.documentElement.classList 是唯一安全操作目标
切换主题时只能动 document.documentElement,不能碰 document.body:
- Next.js/Nuxt 等 SSR 框架依赖
html元素上的dark类做 hydration 对齐;改body会触发不一致、首屏闪白甚至 hydration error - Tailwind 默认只检查
html元素,darkMode: 'class'下不识别body.dark - 示例正确写法:
document.documentElement.classList.toggle('dark')
初始化脚本必须内联在 里,且早于 CSS 加载
“闪白”本质是浏览器先渲染无 dark 类的浅色样式,再等 JS 执行才加类。解决方式只有提前执行:
- 脚本不能挂
DOMContentLoaded或window.onload,太晚 - 必须写成
<script>...</script>内联形式 - 逻辑要立即读
localStorage.theme, fallback 到window.matchMedia('(prefers-color-scheme: dark)'),然后立刻操作document.documentElement - 典型初始化代码(放
内):
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
切换函数必须同步更新 localStorage 和 documentElement
只改 DOM 或只存 localStorage 都会导致状态错乱:
- 刷新丢失:没存
localStorage.theme→ 下次加载还是系统偏好值 - 服务端/客户端不一致:SSR 渲染时没拿到当前 localStorage 值 → hydration mismatch
- 推荐切换函数写法(React 场景下可封装为自定义 Hook):
function toggleDarkMode() {
const isDark = document.documentElement.classList.contains('dark')
if (isDark) {
document.documentElement.classList.remove('dark')
localStorage.theme = 'light'
} else {
document.documentElement.classList.add('dark')
localStorage.theme = 'dark'
}
}
注意:不要用 localStorage.removeItem('theme') 来“重置”,这会让下次加载退回到系统偏好,用户意图丢失。
最易忽略的一点:深色模式不是颜色反转,dark:bg-slate-800 和 bg-white 的对比度、层级感、可读性都要单独验证,尤其文字与背景的 WCAG AA/AAA 合规性。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











