sass实现暗黑/亮色主题需分层定义语义变量与主题映射,用map存储各主题完整视觉属性(颜色、圆角、阴影等),通过独立入口文件分别编译light.css/dark.css,避免@media或条件编译导致的冗余与覆盖问题。

如何用Sass变量定义暗黑/亮色主题
核心是把颜色、背景、边框等视觉属性抽成可切换的变量,而不是写死在选择器里。Sass本身不感知“系统暗色”,它只负责编译出两套CSS——你得靠外部机制(比如class切换)来激活其中一套。
常见错误是直接在$primary-color里写#007bff,结果换主题时要改十几处变量。正确做法是分层:基础语义变量(如$color-text-primary) + 主题映射(如$theme-dark和$theme-light)。
- 用
map结构组织主题,比如$theme-dark: ("text": #e0e0e0, "bg": #121212) - 用
map-get($theme-dark, "text")取值,避免硬编码 - 所有颜色相关CSS属性(
color、background-color、border-color)都走这个映射 - 别在
@media (prefers-color-scheme: dark)里写Sass逻辑——那是运行时,Sass是编译时
如何生成两套独立CSS文件(light.css / dark.css)
Sass不自动输出多主题CSS;你得手动为每个主题建入口文件,再分别编译。否则所有颜色会混在一起,导致暗色样式被亮色覆盖(因为CSS层叠顺序问题)。
典型错误是只写一个main.scss,然后在里面用@if $mode == 'dark'条件编译——这会把两套规则塞进同一份CSS,class切换时无法精准控制作用域。
- 建两个入口:
light.scss(导入$theme: $theme-light)和dark.scss(导入$theme: $theme-dark) - 所有组件样式文件(如
_button.scss)只用map-get($theme, "text"),不关心当前是哪个主题 - 用构建工具(如dart-sass CLI)分别编译:
sass light.scss:light.css和sass dark.scss:dark.css - HTML里通过
<link rel="stylesheet" href="light.css">或<link rel="stylesheet" href="dark.css">切换,而非用class="dark"加CSS-in-JS
为什么不能依赖@media (prefers-color-scheme: dark)自动切主题
这个媒体查询只能触发浏览器原生暗色偏好,但无法让Sass在编译时生成条件逻辑。如果你在Sass里写@media (prefers-color-scheme: dark) { color: map-get($theme-dark, "text") },它只会把dark.css里的规则也编译进去,造成冗余和冲突。
更关键的是:用户可能手动切换主题(比如右上角点个太阳/月亮图标),这时候prefers-color-scheme根本不会变,纯靠它就失效了。
-
@media (prefers-color-scheme: dark)适合做「默认回退」,比如首次加载时按系统偏好选CSS文件 - 真正切换必须靠JS控制
<link>的href,或切换并配合CSS-in-CSS(即用.dark .btn这种层级覆盖) - 如果坚持用class切换方案,Sass里就得写两套选择器:
.btn { color: map-get($theme-light, "text"); } .dark .btn { color: map-get($theme-dark, "text"); }
变量命名和维护最容易踩的坑
很多人起名像$dark-bg、$light-text,看着直观,但一加新主题(比如高对比度模式)就崩——变量名和主题强耦合,没法复用。
另一个隐形问题是:字体大小、阴影、圆角这些非颜色属性,也得进主题map。否则暗色模式下按钮还是亮色的圆角+阴影,违和感极强。
- 统一用语义名:
$color-bg-canvas、$color-text-secondary、$radius-sm、$shadow-md - 每个主题map必须包含完整维度:颜色、间距、圆角、阴影、字体大小、光标
- 用
@function theme-get($key)封装取值逻辑,后续加校验或fallback更方便 - 别在组件里直接引用
$theme-dark——组件只认$theme,由入口文件注入
主题切换不是换个变量名的事,它要求你把所有视觉决策从CSS声明里拎出来,变成可配置的数据结构。最麻烦的永远不是编译,而是想清楚哪些该进主题map、哪些该保持固定——比如品牌主色在暗色模式下通常也要微调亮度,但logo图标颜色往往强制不变。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











