darkmode 必须配置为顶层字段 darkmode: 'class' 或 'media',否则 dark: 类不会生成;html 根元素需有 dark 类才能触发变体;js 初始化须内联执行以避免“闪白”;还需显式添加 dark: 变体并配合 css 变量统一管理主题色。

tailwind.config.js 里 darkMode 没配或配错
dark: 类根本不会生成,不是失效,是压根没进最终 CSS 文件——连警告都不会抛。常见错法包括:darkMode: true、darkMode: 'dark'、darkMode 写在 theme.extend 里,或者 TypeScript 配置类型导出不全导致整个 config 没加载。
必须写成顶层字段,且只接受两个值:darkMode: 'class' 或 darkMode: 'media'。v4 没新增选项,也没默认值。
- 选
'class':后续所有切换逻辑都得靠 JS 操作document.documentElement.classList - 选
'media':CSS 自动响应prefers-color-scheme,但无法手动干预,也不读localStorage
HTML 根元素上没有 dark 类
Tailwind 的 dark: 变体只在 元素上存在 dark 类时才触发,不是靠系统偏好自动生效,也不是看 或某个容器。常见错误是把 dark 加到 上,结果 dark:bg-gray-900 完全没反应。
验证方法:打开 DevTools,选中 元素,确认 class 列表里有 dark;没有就手动加进去测试:。能生效再撤掉,换成 JS 动态控制。
- 绝对不要写
document.body.classList.toggle('dark')——Tailwind 默认只检查document.documentElement - SSR 框架(Next.js/Nuxt)中给
body加dark类会引发 hydration mismatch - 如果用了自定义
darkSelector(比如插件改成了my-dark-mode),那也要对应改 class 名,不能硬写dark
JS 初始化太晚,导致“闪白”
“闪白”不是 bug,是执行时机问题:浏览器先渲染无 dark 类的浅色样式,JS 后加类才触发深色——中间有可见延迟。把初始化逻辑塞进 useEffect、DOMContentLoaded 或 window.onload,页面已经按亮色渲染完了。
必须把判断逻辑写成立即执行函数,内联在 里、<link rel="stylesheet"> 之前:
(() => {
try {
const saved = localStorage.getItem('theme')
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
const shouldDark = saved === 'dark' || (saved !== 'light' && prefersDark)
document.documentElement.classList.toggle('dark', shouldDark)
} catch {}
})()
- 服务端渲染时
window不存在,所以必须包try/catch - 脚本不能挂载到外部文件或延迟加载,必须内联
- 切换时要同步更新
document.documentElement.classList、localStorage.setItem('theme', 'dark')和监听storage事件,否则跨标签页不同步
写了 dark: 却没配对应颜色变体
配完 darkMode: 'class' 只是开了门,真正让暗黑模式可用,还得每处颜色都补上 dark: 变体——比如 text-gray-700 在深色下可能还是灰得看不清,得显式写成 dark:text-gray-300。
最容易被忽略的是:CSS 规则写了却没生效,往往不是媒体查询或 JS 问题,而是你只改了背景,但 h1、.card、button 等元素根本没配深色规则,它们就沿用默认浅色样式。
- 伪类或内联样式可能绕过主题逻辑,需统一用带前缀的选择器覆盖
- 推荐结合 CSS 变量:在
:root定义--text/--bg,再在.dark下重写,所有颜色用color: var(--text),避免硬编码 - 别指望父级“自动传递主题”,
dark:不继承,只看最近的、带dark类的祖先(通常是html)
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











