向 Next.js 项目添加 Sass 主题的最简单方法
需要克服的挑战
尽管 Sass 功能强大,可以编写更简洁、更模块化的 CSS,但它在运行时主题方面存在局限性,因为 Sass 代码是在浏览器呈现之前编译的。这意味着**纯 Sass 无法在运行时动态切换主题**。但是,通过将 CSS 变量与 Sass 相结合,我们可以用最少的额外努力实现运行时主题。
在 Next.js 中设置主题上下文
上下文提供程序将跨组件管理主题状态。此处的示例代码是为 Next.js 14 项目编写的,但它适用于任何 React 设置。
// ThemeProvider.tsx 'use client' import React, { createContext, FC, useCallback, useContext, useLayoutEffect, useMemo, useState } from 'react'; import './ThemeProvider.scss'; type Theme = 'dark' | 'light'; type ContextReturnType = { theme: Theme; toggleTheme: () => void; }; type Props = { children: React.ReactNode; }; const ThemeContext = createContext({ theme: 'dark', toggleTheme: () => {}, }); const ThemeProvider: FC = ({ children }) => { const [theme, setTheme] = useState (() => { if (typeof window !== 'undefined') { const savedTheme = localStorage.getItem('theme'); return (savedTheme || 'dark') as Theme; } return 'dark'; }); const [isLoading, setIsLoading] = useState(true); const toggleTheme = useCallback(() => { setTheme(prevTheme => { const nextTheme = prevTheme === 'light' ? 'dark' : 'light'; localStorage.setItem('theme', nextTheme); return nextTheme; }); }, []); useLayoutEffect(() => { document.documentElement.className = theme; setIsLoading(false); }, [theme]); const contextValue = useMemo(() => ({ theme, toggleTheme }), [theme, toggleTheme]); if (isLoading) { return null; } return {children} ; }; export const useThemeContext = () => useContext(ThemeContext); export default ThemeProvider;
主题存储在状态中并保存到“localStorage”,因此用户的偏好在会话之间保持不变。“toggleTheme”函数在浅色和深色主题之间切换并更新“localStorage”。我们使用“useLayoutEffect”将主题类应用于 HTML 元素,使我们能够在 Sass 中基于此类设置样式。
使用 Sass 定义主题
接下来,让我们使用 Sass 定义主题样式。我们将创建两个 mixin,即“Text”和“Background”,以处理文本和背景的颜色,但您可以根据需要拥有任意数量的颜色。
// theme.scss @mixin Text($primary, $secondary) { --text-primary: #{$primary}; --text-secondary: #{$secondary}; } @mixin Background($primary, $secondary) { --background-primary: #{$primary}; --background-secondary: #{$secondary}; } .dark { --theme: dark; @include Text('#F9F9F9', '#C6C6C6'); @include Background('#0D0E10', '#1E1F24'); } .light { --theme: light; @include Text('#1C1C1C', '#4A4A4A'); @include Background('#FFFFFF', '#f2f7ff'); }
`Text` 和 `Background` 混合类让我们能够轻松地为每个主题应用配色方案。`.dark` 和 `.light` 类为每个主题定义 CSS 变量。`--theme` 属性让我们能够识别 Sass 样式中哪个主题处于活动状态。您可以使用它来应用特定于主题的样式。
在 Sass 中使用 CSS 变量
为了使我们的主题值在 Sass 中可用,让我们创建一个将 CSS 变量转换为 Sass 变量的辅助函数。
// mixins.scss @function theme($color-name) { @return var(--#{$color-name}); }
`theme` 函数通过名称检索 CSS 变量值,允许您在任何想要访问主题相关样式的 Sass 文件中使用 `theme('text-primary')`。
将主题应用到组件
现在,让我们将这些主题变量应用于组件。以下是使用主题相关颜色设置按钮组件样式的方法。
// Button.module.scss @import 'mixins.scss'; .button { color: theme('text-primary'); background-color: theme('background-primary'); }
“按钮”组件现在使用特定于主题的颜色作为其文本和背景,自动适应活动主题。
结论
按照这些步骤,您可以轻松地在 Next.js 项目中实现动态主题。
您可以在我的网站上找到更多我撰写的文章。