暗色模式 是做什么的?
规则
- 在 Next.js 应用中使用
next-themes — 将应用包裹在 <ThemeProvider attribute="class" defaultTheme="system"> 中
- 使用 CSS 变量定义颜色 — 在
:root (亮色) 和 .dark (暗色) 中定义,通过 var(--background) 引用
- 系统偏好检测:
defaultTheme="system" 会尊重 prefers-color-scheme 媒体查询
- 主题切换组件:在 light/dark/system 之间循环 — 使用来自
next-themes 的 useTheme() 钩子
- Tailwind 集成:在 tailwind 配置中启用
darkMode: "class",使用 dark: 前缀进行覆盖
- 水合修复:通过仅在
useEffect 之后挂载主题切换组件,或使用 suppressHydrationWarning 来抑制水合不匹配
- 持久化:
next-themes 将偏好存储在 localStorage 中,并作为 class 应用于 <html> 元素
- 过渡效果:在 body 上添加
transition-colors duration-200 以实现平滑的主题切换
模式
import { ThemeProvider } from "next-themes";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
</body>
</html>
);
}
"use client";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return null;
return (
<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
{theme === "dark" ? "☀️" : "🌙"}
</button>
);
}
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
}
避免
- 硬编码颜色而非使用 CSS 变量 — 会导致无法实现主题切换
- 忘记在
<html> 上使用 suppressHydrationWarning — 会导致水合错误
- 错误主题闪烁:确保
next-themes 脚本在绘制前运行(默认情况下它会这样做)
- 仅支持亮色/暗色而不提供系统选项 — 应尊重用户的操作系统偏好