Tailwind CSS 深色模式怎么实现,常用 dark 类有哪些?
Tailwind CSS 做深色模式,核心不是写两套 CSS,而是选好触发方式,然后在需要变化的地方加 dark: 变体。常见写法大概分两类:跟随系统的 media,以及由页面上的 .dark 或自定义选择器控制的 class/selector。前者省事,后者更适合带主题切换按钮的产品。
先选深色模式触发方式
media 使用浏览器的 prefers-color-scheme,用户系统是深色,页面就走深色样式。
jsexport default { darkMode: 'media' }
适合页面不需要主题切换按钮、希望完全尊重系统设置的情况。缺点是用户不能在站内单独选择浅色或深色。
如果需要按钮切换,推荐用选择器控制。旧项目里常见 class,新一点的 Tailwind v3.4+ 更推荐 selector。
jsexport default { darkMode: 'selector' }
页面上加:
html<html class="dark">
Tailwind v4 更偏 CSS-first。如果要用 .dark 或 data-theme 控制,可以在 CSS 里自定义变体:
css@import 'tailwindcss'; @custom-variant dark (&:where(.dark, .dark *));
或者:
css@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
常用 dark: 类怎么写
Tailwind 的深色模式不是单独的一套类,而是在原有工具类前面加 dark:。
html<div class="rounded-xl border border-slate-200 bg-white p-6 text-slate-900 shadow-sm dark:border-slate-800 dark:bg-slate-950 dark:text-slate-100 dark:shadow-slate-950/40"> <h2 class="text-lg font-semibold text-slate-900 dark:text-white">账户设置</h2> <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">这里会跟随当前主题切换颜色。</p> </div>
项目里最常用的是背景、文字、边框、阴影、hover、表单占位文字、分割线和 focus ring:
html<input class="border-slate-300 bg-white text-slate-900 placeholder:text-slate-400 focus:ring-blue-500 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-100 dark:placeholder:text-slate-500 dark:focus:ring-blue-400" />
实际写组件时,不要所有颜色都硬编码成黑白。深色模式最舒服的搭配通常是深灰背景、浅灰文字、略低对比的边框。
用 JS 和 localStorage 保存用户选择
手动切换时,至少要处理三种状态:浅色、深色、跟随系统。
jsfunction applyTheme(theme) { const root = document.documentElement const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches const shouldUseDark = theme === 'dark' || (!theme && systemDark) root.classList.toggle('dark', shouldUseDark) } const savedTheme = localStorage.getItem('theme') applyTheme(savedTheme) function setTheme(theme) { if (theme) localStorage.setItem('theme', theme) else localStorage.removeItem('theme') applyTheme(theme) }
如果用 data-theme,把 classList.toggle('dark') 换成设置属性即可。
React / Vue 接入和避免闪烁
React 或 Vue 的切换按钮可以放在组件里,但首次应用主题最好用一段很短的内联脚本提前做。否则页面会先按亮色渲染,JavaScript 加载后再切深色,产生 FOUC 闪烁。
html<script> try { const theme = localStorage.getItem('theme') const systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches if (theme === 'dark' || (!theme && systemDark)) { document.documentElement.classList.add('dark') } } catch (e) {} </script>
SSR 框架里还要注意服务端无法直接读取 localStorage。可以用 cookie 保存主题,或者接受首次渲染由内联脚本修正。
对比度和检查清单
深色模式不是把颜色反过来。正文建议至少满足 WCAG 常规文本 4.5:1 的对比度。按钮 hover、focus ring、错误提示、禁用态、图标、表格边框都要单独看。
实现前可以按这个清单过一遍:确认策略,确认 Tailwind 版本,根节点统一用 .dark 或 data-theme,常用类补齐,保存用户选择,提前执行脚本避免闪烁,测试对比度,测试系统主题变化。
Tailwind 的深色模式写起来不难,难的是别漏状态。触发方式选对,组件里坚持用 dark: 写差异,再把本地存储、FOUC 和对比度检查补上,这套方案就能稳定用在真实项目里。