必须显式配置 darkmode: 'class',否则 dark: 类在编译时被彻底剔除;它只能位于 tailwind.config.js 顶层,值仅限 'class' 或 'media';dark 类必须加在 上,动态切换需用 document.documentelement.classlist.toggle('dark');防闪白须内联初始化脚本于 ,并配对使用 transition 类。

必须显式配置 darkMode: 'class',否则所有 dark: 类在编译时被彻底剔除——不是不生效,是压根没生成 CSS 规则。
tailwind.config.js 必须写对位置和值
常见错误是把 darkMode 塞进 theme 或 plugins 里,或者写成 true、'dark'、''。它只能出现在配置文件顶层,且只接受两个合法值:
-
darkMode: 'class'→ 支持手动切换 +localStorage持久化,是唯一能做开关的方案 -
darkMode: 'media'→ 完全响应系统偏好,JS 切换无效,刷新也不丢失,但无法手动干预
改完必须重启构建服务(如 npm run dev),Tailwind 不热更配置项。
dark: 类生效的前提是 有 dark 类
Tailwind 默认只检查 document.documentElement(即 元素)上是否存在 dark 类。加在 或任意子元素上,dark:bg-gray-800 都不会匹配。
- 验证是否生效:直接在 HTML 模板中写
,再测样式 - 动态切换必须用
document.documentElement.classList.toggle('dark') - SSR 框架(如 Next.js)中若操作
body,会导致 hydration 失败或首屏闪白
防“闪白”必须内联初始化脚本
浏览器先渲染无 dark 类的浅色样式,JS 后加类才触发深色——这个延迟就是“闪白”。解决方式只有一种:脚本必须内联在 中,且早于 CSS 加载。
- 不能挂
DOMContentLoaded或window.onload(太晚) - 必须包裹
try/catch(服务端无window) - 要同时读取
localStorage.getItem('theme')和window.matchMedia('(prefers-color-scheme: dark)')做 fallback
最小可行脚本(可直接贴入 ):
(() => {
try {
const stored = localStorage.getItem('theme')
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches
const shouldDark = stored === 'dark' || (stored !== 'light' && prefersDark)
document.documentElement.classList.toggle('dark', shouldDark)
} catch {}
})()
transition 要配对使用,且只对可动画属性有效
transition 类本身不触发变化,只定义“怎么变”。没有起始态和结束态的样式差异,过渡就完全静默。
- 正确姿势永远是成对出现:
bg-white dark:bg-gray-800+transition-colors,或opacity-100+hover:opacity-75 - 优先用
transform和opacity:GPU 加速,无重排,最稳;避免width、height、display等不可过渡属性 -
transition-all会连box-shadow、filter一起过渡,可能抖动,建议明确写transition-transform或transition-opacity
复杂点在于:深色模式切换本身是类名增删,不是属性渐变,所以颜色过渡依赖 transition-colors,而背景/文字色切换是否平滑,取决于你有没有给对应属性加 transition- 前缀,以及是否避开了不可动画的属性。最容易被忽略的是——配了 darkMode: 'class' 只是开了门,真正让过渡可用,还得每处颜色都补上 transition- 类,并确保状态切换逻辑不触发隐式重排。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











