什么是深色模式
深色模式(Dark Mode)已经成为现代 Web 应用的标准特性之一。它不仅可以减少眼睛疲劳,还能在 OLED 屏幕上节省电量。Tailwind CSS 提供了强大而灵活的深色模式支持,使得实现这一特性变得简单直观。
Tailwind CSS 深色模式策略
Tailwind CSS 支持两种深色模式策略:
1. 媒体查询策略(默认)
这种策略基于用户的系统偏好设置,通过 prefers-color-scheme 媒体查询自动切换。
// tailwind.config.js
module.exports = {
darkMode: 'media', // 或者不设置,默认就是 'media'
// ...
}
使用方法:
<div class="bg-white dark:bg-gray-900">
<h1 class="text-gray-900 dark:text-white">标题</h1>
<p class="text-gray-600 dark:text-gray-300">内容</p>
</div>
2. 类名策略(推荐)
这种策略允许你通过添加 dark 类名来手动控制深色模式,提供了更大的灵活性。
// tailwind.config.js
module.exports = {
darkMode: 'class',
// ...
}
实现深色模式切换
基础实现
<!DOCTYPE html>
<html lang="zh-CN" class="dark">
<head>
<!-- ... -->
</head>
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
<button id="theme-toggle">切换主题</button>
<script>
const toggle = document.getElementById('theme-toggle');
const html = document.documentElement;
toggle.addEventListener('click', () => {
html.classList.toggle('dark');
localStorage.setItem('theme', html.classList.contains('dark') ? 'dark' : 'light');
});
// 页面加载时恢复用户偏好
if (localStorage.getItem('theme') === 'dark') {
html.classList.add('dark');
}
</script>
</body>
</html>
进阶实现:支持系统偏好
function initTheme() {
const savedTheme = localStorage.getItem('theme');
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (savedTheme === 'dark' || (!savedTheme && systemPrefersDark)) {
document.documentElement.classList.add('dark');
}
}
// 在页面加载前执行,避免闪烁
initTheme();
// 监听系统主题变化
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
if (!localStorage.getItem('theme')) {
document.documentElement.classList.toggle('dark', e.matches);
}
});
设计系统配置
颜色方案设计
在设计深色模式时,不应该简单地反转颜色。以下是一些最佳实践:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
// 浅色模式主色
primary: {
50: '#f0f9ff',
100: '#e0f2fe',
// ...
900: '#0c4a6e',
},
// 深色模式使用不同的灰度
gray: {
50: '#f9fafb',
100: '#f3f4f6',
// ...
900: '#111827',
950: '#030712', // 深色模式专用
},
},
},
},
}
语义化颜色变量
使用 CSS 变量可以更好地管理颜色:
@layer base {
:root {
--color-bg-primary: 255 255 255;
--color-bg-secondary: 249 250 251;
--color-text-primary: 17 24 39;
--color-text-secondary: 107 114 128;
}
.dark {
--color-bg-primary: 17 24 39;
--color-bg-secondary: 31 41 55;
--color-text-primary: 249 250 251;
--color-text-secondary: 209 213 219;
}
}
在 Tailwind 中使用:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
'bg-primary': 'rgb(var(--color-bg-primary) / <alpha-value>)',
'bg-secondary': 'rgb(var(--color-bg-secondary) / <alpha-value>)',
'text-primary': 'rgb(var(--color-text-primary) / <alpha-value>)',
'text-secondary': 'rgb(var(--color-text-secondary) / <alpha-value>)',
},
},
},
}
常见问题和解决方案
1. 页面闪烁问题
在页面加载时,如果 JavaScript 执行较慢,可能会出现主题闪烁。解决方法是将主题初始化脚本放在 <head> 中:
<head>
<script>
(function() {
const theme = localStorage.getItem('theme');
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (theme === 'dark' || (!theme && systemPrefersDark)) {
document.documentElement.classList.add('dark');
}
})();
</script>
</head>
2. 图片在深色模式下的处理
某些图片在深色背景下可能不太合适,可以使用以下技巧:
<!-- 方法 1: 使用不同的图片 -->
<img src="logo-light.png" class="dark:hidden" alt="Logo" />
<img src="logo-dark.png" class="hidden dark:block" alt="Logo" />
<!-- 方法 2: 调整透明度 -->
<img src="image.png" class="dark:opacity-80" alt="Image" />
<!-- 方法 3: 使用滤镜 -->
<img src="image.png" class="dark:invert" alt="Image" />
3. 第三方组件样式
对于第三方组件,可能需要额外的样式覆盖:
.dark .third-party-component {
@apply bg-gray-800 text-white;
}
性能优化
减少类名数量
过多的 dark: 前缀会增加 CSS 文件大小。可以使用 CSS 变量来减少类名:
<!-- 不推荐 -->
<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white border-gray-200 dark:border-gray-700">
<!-- ... -->
</div>
<!-- 推荐 -->
<div class="bg-bg-primary text-text-primary border-border-primary">
<!-- ... -->
</div>
懒加载深色模式样式
对于大型应用,可以考虑按需加载深色模式样式:
if (document.documentElement.classList.contains('dark')) {
import('./styles/dark-mode.css');
}
总结
Tailwind CSS 的深色模式支持为开发者提供了强大而灵活的工具。通过合理的配置和最佳实践,你可以轻松实现一个美观、高性能的深色模式设计系统。记住以下关键点:
- 选择合适的深色模式策略(类名或媒体查询)
- 使用语义化的颜色变量
- 避免简单的颜色反转,设计专门的深色配色方案
- 处理好页面闪烁和图片显示问题
- 注意性能优化,减少不必要的类名