向 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 项目中实现动态主题。
您可以在我的网站上找到更多我撰写的文章。