纯 sass 无法实现 css-in-js 的运行时响应能力,所有逻辑均在编译期固化为静态 css;可通过 @function 封装确定性计算、@if/@each 控制输出分支,并借助 :export 与 js 共享配置型变量。

纯 Sass 无法实现 CSS-in-JS 那种运行时响应 props/state/theme 的能力——它在编译期就结束了,所有逻辑都固化成静态 CSS。但你可以用 Sass 的函数、控制指令和设计模式,模拟出“类似”的逻辑表达力,关键在于分清「编译期能做什么」和「必须交给 JS 做什么」。
用 @function 封装可复用的计算逻辑
Sass 函数适合做确定性、无副作用的数值转换,比如单位换算、比例计算、颜色派生。它不是为了替代 JS 的条件渲染,而是把重复的手动计算变成一次定义、多处调用。
-
@function必须返回一个值(不能生成 CSS 规则),所以别指望它能根据变量动态插入整套 dark mode 样式块 - 常见误用:写一个
@function get-color($role)返回#333或#111,然后在每个属性里手动调用——这没解决维护问题,反而让样式更难读 - 正确思路:把真正需要变化的维度抽出来,比如
$theme-map: (light: (bg: #fff, text: #333), dark: (bg: #111, text: #eee)),再用@function theme-value($theme, $key)查表取值 - 注意单位一致性:
1rem * 1.2合法,16px + 1rem非法;混单位要先转成数字,再乘基准(如unitless(1rem) * 16px)
用 @if/@each 控制 CSS 输出分支
想让 Sass “决策”是否生成某段样式,必须用控制指令(@if、@each),而不是 if() 函数。后者只返回一个值,前者决定代码是否被写入最终 CSS。
- 典型错误:
color: if($dark-mode, #fff, #000)—— 这只会输出一个固定颜色,无法删掉 light 模式下的整套规则 - 正确做法:用
@if $dark-mode { ... }分别包裹两套规则块,或者用@each $mode, $config in $themes { .#{$mode}-theme { ... } }批量生成主题类 - 避免嵌套爆炸:别在
@each里再套@media,否则每个主题都会复制一遍全部断点,体积翻倍 - 业务真实需求优先:只遍历
$used-themes: (light, dark),而不是硬写(light, dark, high-contrast, sepia)却只用前两个
与 JavaScript 共享变量的边界在哪
Sass 变量无法在运行时被 JS 读取或修改,但可以通过构建流程导出为 JS 可访问的对象——前提是你的打包器支持(如 Webpack + css-loader + :export)。
- 必须显式声明:
:export { primaryColor: $primary-color; spacingSm: $space-sm; },否则 JS 什么都拿不到 - 导出的是编译时快照,JS 修改它不会反向影响 Sass;反过来,JS 改变状态也不会触发 Sass 重编译
- 适合导出配置型数据(颜色、间距、断点值),不适合导出逻辑(比如“当前是否深色模式”这种状态)
- 如果项目用 Vite,
:export不原生支持,得配vite-plugin-sass-export或改用 JSON 配置双写
最常被忽略的一点:所谓“复杂算法”,90% 的场景其实只需要 Sass 做好静态计算和结构组织,真正的动态响应仍要靠 JS 驱动 class 切换或 CSS 自定义属性更新。硬要在 Sass 里模拟运行时逻辑,最后往往卡在编译期求值限制上,反而增加理解成本。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











