主题变量用扁平Map定义,如("primary": #1890ff),通过@each生成:data-theme对应CSS变量,组件统一用var()引用,JS仅切换data-theme属性并持久化。

用 Map 存储组件主题的 CSS 变量,核心是把“主题名 → 颜色/尺寸/阴影等值”变成结构化、可遍历、易维护的键值对,而不是散落的变量或重复的文件。
主题 Map 必须扁平、语义化、统一格式
定义时避免嵌套过深,键用带引号字符串(如 "primary"),值直接对应具体颜色、尺寸或函数调用结果。例如:
- $theme-vars: (
- "primary": #1890ff,
- "bg": #ffffff,
- "border-radius": 6px,
- "shadow-sm": "0 1px 2px rgba(0,0,0,0.05)"
- );
不推荐写成 $primary-color: #1890ff; 或嵌套 light: (colors: (primary: ...)) —— Sass/Less 对深层路径访问支持弱,容易报错或取不到值。
用 @each 遍历 Map 生成 :root[data-theme] 规则
每个主题对应一个 :root[data-theme="xxx"] 块,里面挂载对应的 CSS 自定义属性:
立即学习“前端免费学习笔记(深入)”;
- @each $name, $vars in $theme-vars {
- :root[data-theme="#{$name}"] {
- --primary: #{map-get($vars, "primary")};
- --bg: #{map-get($vars, "bg")};
- --radius: #{map-get($vars, "border-radius")};
- }
- }
注意:#{} 插值必须包裹 map-get(),否则输出的是函数文本而非实际值;data-theme 的值要和 Map 键严格一致(包括引号、大小写)。
组件样式统一使用 var() 引用,不硬编码
按钮、卡片、表单等组件内部,全部通过 var(--primary)、var(--radius) 调用,例如:
- .btn {
- background-color: var(--primary);
- border-radius: var(--radius);
- box-shadow: var(--shadow-sm);
- }
这样切换主题只需改 html 元素的 data-theme 属性,所有组件自动响应,无需重写样式逻辑。
配合 JS 控制切换并持久化偏好
前端运行时靠 JavaScript 切换主题,并存入 localStorage:
- 点击按钮时设置 document.documentElement.setAttribute('data-theme', 'dark')
- 页面加载时读取 localStorage.getItem('theme') 并还原
- 可监听 prefers-color-scheme 做系统级兜底
此时 CSS 变量已由预处理器提前生成好,JS 只负责开关,无编译开销,无闪烁风险。


















