暗黑模式设计完整方案
暗黑模式已成为现代应用的标准功能。它能够减少眼睛疲劳、节省电池、改善用户体验。
核心色彩系统
Light Mode 配色
:root {
/* Light Mode */
--bg-primary: #ffffff;
--bg-secondary: #f5f5f5;
--bg-tertiary: #efefef;
--text-primary: #1a1a1a;
--text-secondary: #666666;
--text-tertiary: #999999;
--border-color: #e0e0e0;
--divider-color: #f0f0f0;
}
Dark Mode 配色
@media (prefers-color-scheme: dark) {
:root {
/* Dark Mode */
--bg-primary: #1a1a1a;
--bg-secondary: #2d2d2d;
--bg-tertiary: #3a3a3a;
--text-primary: #ffffff;
--text-secondary: #e0e0e0;
--text-tertiary: #a0a0a0;
--border-color: #404040;
--divider-color: #2a2a2a;
}
}
实现方案
方案 1:prefers-color-scheme
/* 自动跟随系统设置 */
@media (prefers-color-scheme: light) {
:root {
--bg: #fff;
--text: #000;
}
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #1a1a1a;
--text: #fff;
}
}
body {
background: var(--bg);
color: var(--text);
}
方案 2:JavaScript 切换
// 检测和切换暗黑模式
function initDarkMode() {
const isDark = localStorage.getItem('darkMode') === 'true' ||
window.matchMedia('(prefers-color-scheme: dark)').matches;
if (isDark) {
document.documentElement.setAttribute('data-theme', 'dark');
}
}
function toggleDarkMode() {
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
const newTheme = isDark ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('darkMode', newTheme === 'dark');
}
// CSS 应用
html[data-theme='light'] {
color-scheme: light;
}
html[data-theme='dark'] {
color-scheme: dark;
}
方案 3:CSS Variables + JavaScript
const themes = {
light: {
'--bg-primary': '#ffffff',
'--text-primary': '#000000',
'--accent': '#0066cc',
'--border': '#e0e0e0',
},
dark: {
'--bg-primary': '#1a1a1a',
'--text-primary': '#ffffff',
'--accent': '#4da3ff',
'--border': '#404040',
},
};
function applyTheme(themeName) {
const theme = themes[themeName];
Object.entries(theme).forEach(([key, value]) => {
document.documentElement.style.setProperty(key, value);
});
localStorage.setItem('theme', themeName);
}
对比度管理
/* Light Mode 对比度 */
:root {
--contrast-high: #000000; /* 21:1 */
--contrast-medium: #333333; /* 12.6:1 */
--contrast-low: #666666; /* 5.1:1 */
}
/* Dark Mode 对比度 */
@media (prefers-color-scheme: dark) {
:root {
--contrast-high: #ffffff; /* 21:1 */
--contrast-medium: #e0e0e0; /* 11.6:1 */
--contrast-low: #a0a0a0; /* 4.5:1 */
}
}
/* 应用对比度 */
.text-primary { color: var(--contrast-high); }
.text-secondary { color: var(--contrast-medium); }
.text-tertiary { color: var(--contrast-low); }
图片和图表处理
<!-- 针对不同主题的图片 -->
<picture>
<source
media="(prefers-color-scheme: dark)"
srcset="chart-dark.svg"
/>
<img src="chart-light.svg" alt="图表" />
</picture>
<!-- SVG 颜色适配 -->
<svg class="icon">
<circle cx="50" cy="50" r="40" fill="currentColor" />
</svg>
<style>
.icon {
color: var(--text-primary);
}
</style>
完整示例
import { useState, useEffect } from 'react';
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
// 获取保存的主题或系统偏好
const savedTheme = localStorage.getItem('theme');
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
const initialTheme = savedTheme || systemTheme;
setTheme(initialTheme);
document.documentElement.setAttribute('data-theme', initialTheme);
}, []);
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
localStorage.setItem('theme', newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
};
// 防止闪烁
if (!mounted) {
return null;
}
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
<ThemeToggle theme={theme} onChange={toggleTheme} />
</ThemeContext.Provider>
);
}
function ThemeToggle({ theme, onChange }) {
return (
<button
onClick={onChange}
aria-label={`切换到${theme === 'light' ? '暗黑' : '亮色'}模式`}
>
{theme === 'light' ? '🌙' : '☀️'}
</button>
);
}
最佳实践
✅ 应该做的事:
- 支持系统偏好
- 提供手动切换选项
- 确保足够的对比度
- 优化图片和图表
- 防止加载闪烁
❌ 不应该做的事:
- 强制单一模式
- 忽视性能影响
- 使用相同的颜色
- 忘记保存用户偏好
- 过度使用深色背景
测试清单
- 在浅色和深色模式下测试所有页面
- 检查颜色对比度符合 WCAG 标准
- 验证图片和图表在两种模式下清晰
- 测试主题切换的平滑性
- 检查用户偏好是否被保存


