动态主题切换的实现方式
1. 使用 CSS 变量(CSS Custom Properties)
CSS 变量是实现主题切换最直接的方式:
:root {
--primary-color: #4285f4;
--background-color: #ffffff;
--text-color: #333333;
}
[data-theme="dark"] {
--primary-color: #8ab4f8;
--background-color: #1a1a1a;
--text-color: #f1f1f1;
}
body {
background-color: var(--background-color);
color: var(--text-color);
}
JavaScript 切换主题:
function toggleTheme() {
document.documentElement.setAttribute('data-theme',
document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'
);
}
2. CSS-in-JS 实现(以 styled-components 为例)
import styled, { ThemeProvider } from 'styled-components';
const lightTheme = {
primary: '#4285f4',
background: '#ffffff',
text: '#333333'
};
const darkTheme = {
primary: '#8ab4f8',
background: '#1a1a1a',
text: '#f1f1f1'
};
const Button = styled.button`
background: ${props => props.theme.primary};
color: ${props => props.theme.text};
`;
function App() {
const [theme, setTheme] = useState(lightTheme);
const toggleTheme = () => {
setTheme(theme === lightTheme ? darkTheme : lightTheme);
};
return (
<ThemeProvider theme={theme}>
<Button onClick={toggleTheme}>Toggle Theme</Button>
</ThemeProvider>
);
}
提升首屏渲染效率的策略
1. 关键 CSS 提取
// 使用 styled-components 的 ServerStyleSheet 提取关键 CSS
import { ServerStyleSheet } from 'styled-components';
const sheet = new ServerStyleSheet();
const html = renderToString(sheet.collectStyles(<App />));
const styleTags = sheet.getStyleTags(); // 插入到 HTML 的 head 中
2. 代码分割与按需加载
import React, { lazy, Suspense } from 'react';
const HeavyComponent = lazy(() => import('./HeavyComponent'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<HeavyComponent />
</Suspense>
);
}
3. 使用 CSS 变量替代动态样式
CSS 变量的性能优于 JavaScript 动态计算样式:
// 不推荐 - 性能较差
const DynamicDiv = styled.div`
color: ${props => props.color};
`;
// 推荐 - 使用 CSS 变量
const DynamicDiv = styled.div`
color: var(--dynamic-color);
`;
// 使用时
<DynamicDiv style={{ '--dynamic-color': props.color }} />
4. 避免不必要的重新渲染
// 使用 React.memo 避免不必要的重新渲染
const ThemedButton = React.memo(styled.button`
background: ${props => props.theme.primary};
`);
CSS 变量如何解决这些问题
1. 主题切换性能优化
CSS 变量在浏览器层面实现样式更新,避免了 JavaScript 的样式计算和 DOM 操作:
// 只需改变根元素的变量值
document.documentElement.style.setProperty('--primary-color', newColor);
2. 首屏渲染优化
CSS 变量:
-
可以被预解析,浏览器可以更快地构建渲染树
-
减少 CSS-in-JS 运行时生成的样式表大小
-
支持服务器端渲染,不会产生样式闪烁
3. 动态样式与静态样式的分离
/* 静态部分编译时确定 */
.button {
padding: 8px 16px;
border-radius: 4px;
/* 动态部分通过变量控制 */
background: var(--button-bg, #eee);
color: var(--button-color, #333);
}
4. 主题持久化示例
结合 localStorage 实现主题持久化:
// 初始化主题
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
// 切换主题并保存
function toggleTheme() {
const newTheme = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
}
性能对比
方案 | 首屏渲染 | 主题切换 | 维护性 | SSR支持 |
---|---|---|---|---|
纯 CSS-in-JS | 较慢 | 快 | 好 | 需要额外配置 |
CSS 变量 | 快 | 最快 | 一般 | 原生支持 |
混合方案 | 较快 | 快 | 最好 | 需要配置 |
最佳实践推荐:使用 CSS 变量定义主题色,结合 CSS-in-JS 管理组件样式,既能保证性能又能维护良好的开发体验。