Tailwind 的 dark 变体默认不生效,因它仅是条件前缀,需手动在 <html> 添加 dark 类或配置 darkMode: 'class';须用 JavaScript 控制类切换并持久化至 localStorage,且注意 focus:ring 等样式在深色下的可见性。
系统深色偏好不会被 Tailwind 默认自动监听,手动切换状态也不会由其自行处理,dark: 它仅是一个条件前缀,不会主动触发任何逻辑——需要由你提供 dark 把类名添加到某个祖先元素上之后,它才会生效。
常见误区是直接写 dark:bg-gray-800 却没有在 <html> 或 <body> 上添加 dark 类,导致样式完全无法应用。
<html> 添加或移除 dark 类prefers-color-scheme: dark 媒体查询并配合 class 进行切换(Tailwind 3.3+ 支持 darkMode: 'class' 配置)tailwind.config.js 中已经设置 darkMode: 'class'(而不是 'media'),不然 dark: 变体只会响应媒体查询,无法响应类名一段脚本即可运行,既不使用框架,也省去 localStorage 初始化:
document.documentElement.classList.toggle('dark', localStorage.getItem('theme') === 'dark')document.getElementById('theme-toggle').addEventListener('click', () => { const isDark = document.documentElement.classList.contains('dark') document.documentElement.classList.toggle('dark', !isDark) localStorage.setItem('theme', !isDark ? 'dark' : 'light')})
需要注意:
立即学习“前端免费学习笔记(深入)”;
document.documentElement(也就是 <html>),而非 <body>,否则某些样式(例如 dark:bg-gray-900 用于根级背景时)可能无法生效localStorage 读取会比使用 matchMedia 存储结果优先于系统设置和用户选择之间的冲突,控制更稳定且不会闪屏textContent = isDark ? '亮色' : '深色'
背景色和文字色不必在每个元素上各写两遍,应优先组合语义化工具类:
bg-surface text-content 这类通过 theme.extend.colors 定义的自定义颜色变量,再搭配 dark:bg-surface-dark dark:text-content-dark,即可一处修改、全局切换dark:text-gray-200 dark:bg-gray-800 dark:border-gray-700 连写——可抽成 dark:prose-invert 或自定义 dark-card 类dark:checked:bg-blue-600 要显式写,checked: 和 dark: 可叠加,但顺序不能错(dark:checked:bg- ✅,checked:dark:bg- ❌)Tailwind 的 focus:ring 在深色背景中经常因对比度不够而仿佛“消失”,特别是 focus:ring-blue-500 位于 dark:bg-gray-900 上时几乎看不见。
focus:ring-2 focus:ring-blue-400 dark:focus:ring-blue-300
focus-visible 取代 focus,让 outline 仅响应非鼠标点击的操作(Tailwind 3.0+ 默认启用)focus:outline-none 会产生移除原生 focus 样式的副作用,而深色模式下没有补充时 focus:ring,键盘用户将完全看不到焦点指示真正最容易漏掉的是 CSS 变量过渡与图片适配:切换dark模式时,纯色可以立即变化,但 background-image: url(...) 图片不会自动替换,SVG fill 同样不会自行反色,因此都需要单独处理。