暗黑模式是一项重要的无障碍功能,在长时间编码或在弱光环境下工作时,暗黑模式能够有效缓解眼部疲劳,甚至可以在 OLED 屏幕上节省电量,让你的网站呈现现代感十足且视觉上更具吸引力的外观。本文将探讨如何在 React 项目中使用 tailwindcss 添加暗黑模式。
前置准备
在开始之前,我们需要进行以下准备:
- 一个 React 项目。可以使用 Vite 或者 Next.js 创建一个新的 React 项目,也可以使用已有的项目。
- 已在项目中安装并配置 Tailwind CSS。如果尚未完成此操作,可以查看 Tailwind CSS 官方文档进行配置。
步骤 1: 在 Tailwind CSS 中配置暗黑模式
在引入 tailwindcss
的全局 CSS 文件中进行主题样式配置:
css
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
}
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
}
@layer base {
body {
@apply bg-background text-foreground;
}
}
步骤 2: 创建主题 Context 和 Provider
为了在整个应用程序中全局管理主题状态,这里使用了 React 的 Context API,这种方法可以让任何组件都能轻松的访问和更新当前主题。
tsx
// components/theme-provider.tsx
import { createContext, useContext, useEffect, useState } from "react"
type Theme = "dark" | "light"
type ThemeProviderProps = {
children: React.ReactNode
defaultTheme?: Theme
storageKey?: string
}
type ThemeProviderState = {
theme: Theme
setTheme: (theme: Theme) => void
}
const initialState: ThemeProviderState = {
theme: "light",
setTheme: () => null,
}
const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
export function ThemeProvider({
children,
defaultTheme = "light",
storageKey = "vite-ui-theme",
...props
}: ThemeProviderProps) {
const [theme, setTheme] = useState<Theme>(
() => (localStorage.getItem(storageKey) as Theme) || defaultTheme
)
useEffect(() => {
const root = window.document.documentElement
root.classList.remove("light", "dark")
root.classList.add(theme)
}, [theme])
const value = {
theme,
setTheme: (theme: Theme) => {
localStorage.setItem(storageKey, theme)
setTheme(theme)
},
}
return (
<ThemeProviderContext.Provider {...props} value={value}>
{children}
</ThemeProviderContext.Provider>
)
}
export const useTheme = () => {
const context = useContext(ThemeProviderContext)
if (context === undefined)
throw new Error("useTheme must be used within a ThemeProvider")
return context
}
步骤 3: 创建一个主题切换组件
tsx
// components/mode-toggle.tsx
import { useTheme } from "@/components/theme-provider"
const SunIcon = () => (
<svg
className="h-6 w-6 text-yellow-500"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M12 3v1m0 16v1m9-9h1M3 12H2m15.325-4.675l.707-.707M6.071 18.071l-.707.707M17.325 17.325l.707.707M6.071 6.071l-.707-.707"
></path>
</svg>
)
const MoonIcon = () => (
<svg
className="h-6 w-6 text-gray-500"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"
></path>
</svg>
)
export function ModeToggle() {
const { theme, setTheme } = useTheme()
const toggleTheme = () => {
if (theme === "dark") {
setTheme("light")
} else {
setTheme("dark")
}
}
return (
<button
onClick={toggleTheme}
className="bg-primary text-primary-foreground rounded-md p-2 shadow-xs"
>
{theme === "light" ? <SunIcon /> : <MoonIcon />}
</button>
)
}
步骤 4:将 ThemeProvider 集成到你的应用程序中
tsx
// App.tsx
import { ThemeProvider } from "@/components/theme-provider"
import { ModeToggle } from "@/components/mode-toggle"
function App() {
return (
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
<div className="flex min-h-svh flex-col items-center justify-center">
<ModeToggle />
</div>
</ThemeProvider>
)
}
export default App
步骤 5:使用 Tailwind CSS 应用暗黑模式样式
在写 className
的时候使用 dark:
前缀就可以轻松添加暗黑模式样式。比如 dark:bg-gray-900
。
总结
网站实现暗黑模式(Dark Mode)的必要性已从设计趋势逐渐转变为用户体验的核心需求。本文通过 Tailwind CSS 内置的 dark
变体和 React 的 Context API,实现了暗黑模式主题的切换功能,这一功能可以显著提升用户体验并且让你的网站变得很酷。