1. dark: 前缀基础
Tailwind 通过 dark: 前缀为深色模式提供专属样式。当深色模式激活时,dark: 前缀后的工具类生效,覆盖默认样式。
<!-- 浅色:白色背景 + 深色文字;深色:深色背景 + 浅色文字 -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
自动适应深浅色主题
</div>
<!-- 完整的卡片深色模式 -->
<div class="
bg-white dark:bg-gray-800
border border-gray-200 dark:border-gray-700
text-gray-900 dark:text-gray-100
shadow-sm dark:shadow-gray-900/50
rounded-xl p-6
">
<h3 class="text-lg font-semibold mb-2 text-gray-900 dark:text-white">卡片标题</h3>
<p class="text-gray-600 dark:text-gray-400 text-sm">
卡片描述文字,在深浅色模式下都有良好可读性
</p>
</div>
2. 深色模式策略:media vs class
media 策略(跟随系统)
默认策略。dark: 前缀基于 CSS 媒体查询 @media (prefers-color-scheme: dark),自动跟随用户操作系统的深浅色设置。
/* CSS 等价实现(Tailwind 自动生成)*/
@media (prefers-color-scheme: dark) {
.dark\:bg-gray-900 {
background-color: var(--color-gray-900);
}
}
class 策略(手动切换)
v4 中通过 @variant dark 自定义深色模式策略。将策略改为 class,则当 <html>(或任意祖先元素)有 dark class 时,dark: 前缀生效。
/* src/style.css —— 改为 class 策略 */
@import "tailwindcss";
@variant dark (&:where(.dark, .dark *));
/* 等价于:祖先元素有 .dark 类时,dark: 前缀生效 */
<!-- HTML:手动在 <html> 上切换 dark 类 -->
<html class="dark"> <!-- 深色模式 -->
<html> <!-- 浅色模式 -->
media vs class 选哪个?
如果只需跟随系统偏好,用默认的 media 策略即可。如果需要用户手动切换(网站上有深/浅色切换按钮),必须用 class 策略——因为 media 策略无法通过 JavaScript 控制。
3. 深色模式切换按钮完整实现
以下是一个带持久化(localStorage)的深色模式切换功能,是最常见的实现方式:
<!-- HTML 结构 -->
<button
id="theme-toggle"
class="
p-2 rounded-lg
bg-gray-100 dark:bg-gray-800
text-gray-500 dark:text-gray-400
hover:bg-gray-200 dark:hover:bg-gray-700
transition-colors duration-200
"
aria-label="切换深色模式"
>
<!-- 太阳图标(深色模式时显示)-->
<svg id="icon-sun" class="hidden dark:block w-5 h-5" ...></svg>
<!-- 月亮图标(浅色模式时显示)-->
<svg id="icon-moon" class="block dark:hidden w-5 h-5" ...></svg>
</button>
// JavaScript:深色模式切换逻辑
const html = document.documentElement;
const btn = document.getElementById('theme-toggle');
// 初始化:读取用户偏好或系统设置
function initTheme() {
const saved = localStorage.getItem('theme');
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (saved === 'dark' || (!saved && prefersDark)) {
html.classList.add('dark');
} else {
html.classList.remove('dark');
}
}
// 切换
btn.addEventListener('click', () => {
const isDark = html.classList.toggle('dark');
localStorage.setItem('theme', isDark ? 'dark' : 'light');
});
// 跟随系统变化
window.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
html.classList.toggle('dark', e.matches);
}
});
initTheme(); // 页面加载时执行
避免主题闪烁(FOUC):将 initTheme() 的调用放在 <head> 中的内联 <script> 里(不是 defer),确保 DOM 渲染前就设置好 class,避免浅色→深色的闪烁。
4. CSS 变量 + Tailwind 主题配合
v4 中,深色模式与 CSS 变量结合能创建更灵活的主题系统:
/* 定义亮色 / 暗色主题变量 */
@import "tailwindcss";
@variant dark (&:where(.dark, .dark *));
@theme {
--color-background: white;
--color-surface: #f9fafb;
--color-text-primary: #111827;
--color-text-secondary: #6b7280;
--color-border: #e5e7eb;
}
/* 深色模式覆盖 CSS 变量 */
.dark {
--color-background: #0f172a;
--color-surface: #1e293b;
--color-text-primary: #f1f5f9;
--color-text-secondary: #94a3b8;
--color-border: #334155;
}
<!-- 使用主题变量工具类(v4 自动生成 bg-background 等类)-->
<div class="bg-background text-text-primary border border-border">
<!-- 自动适应深浅色,无需写 dark: 前缀 -->
主题感知组件
</div>
本章小结:小项目用默认 media 策略跟随系统即可;需要手动切换时改用 class 策略,并配合 localStorage 持久化。CSS 变量 + @theme 的组合是构建完整主题系统的最佳实践,让深浅色切换只需改变 CSS 变量值,无需在每个元素上写 dark:。