Dart Sass 通过 type-of() 函数在编译期识别变量类型,返回 color、number、list、map 等字符串;它仅适用于 Sass 变量($foo),不支持 CSS 自定义属性或语义判断,需配合命名约定和单位校验确保降级安全。

怎么在编译期识别 Sass 变量是颜色、尺寸还是列表?
Sass 本身不提供运行时类型检查,但 Dart Sass(当前主流实现)支持 type-of() 函数,可在编译时返回变量的类型字符串。它能区分 color、number、string、list、map、null 等基础类型——这正是生成差异化降级代码的前提。
注意:type-of() 对 CSS 自定义属性(--foo)无效,它只作用于 Sass 编译期变量($foo);也不能识别“语义类型”,比如一个 number 变量是否实际代表像素值,需靠命名或约定辅助判断。
-
type-of($primary-color)→"color" -
type-of($border-radius)→"number" -
type-of($font-stack)→"list" -
type-of($theme)→"map"
用 @if + type-of() 为不同变量类型写后备值
你不能直接把 var(--x) 当作后备值塞进所有属性里——比如 color: var(--c, #000); 合法,但 border-radius: var(--r, 4px); 在旧浏览器里会因单位缺失或语法错误被忽略。所以得按类型分路径处理。
典型做法是在 mixin 中封装逻辑:
立即学习“前端免费学习笔记(深入)”;
@mixin css-var($prop, $var, $fallback) {
@if type-of($fallback) == color {
#{$prop}: $fallback;
#{$prop}: var($var, #{$fallback});
} @else if type-of($fallback) == number {
// 假设 fallback 是带单位的数值(如 8px),直接输出
#{$prop}: $fallback;
#{$prop}: var($var, #{$fallback});
} @else if type-of($fallback) == list {
// 列表通常用于多值属性(如 margin),取第一个值作降级
#{$prop}: nth($fallback, 1);
#{$prop}: var($var, #{nth($fallback, 1)});
} @else {
#{$prop}: $fallback;
#{$prop}: var($var, #{$fallback});
}
}
调用示例:
$primary-color: #326dee;
$border-radius: 8px;
$padding: 1rem 1.5rem;
.button {
@include css-var(color, --primary-color, $primary-color);
@include css-var(border-radius, --border-radius, $border-radius);
@include css-var(padding, --padding, $padding);
}
为什么不能直接用 var(--x, $fallback)?
CSS 语法要求 var() 的后备值必须是**合法的 CSS 值**,而 Sass 变量(如 $primary-color)在未被插值前只是编译器内部符号,不能直接出现在 CSS 输出中。下面写法会报错:
color: var(--c, $primary-color); // ❌ 编译失败:Sass 不允许变量裸露在 CSS 值位置
必须用 #{$primary-color} 显式插值,且该插值只能在字符串上下文或属性值中进行。这也是为什么所有降级逻辑必须在 Sass 层完成,不能指望 CSS 自己“理解” Sass 变量。
另一个坑:如果 $fallback 是 map 或复杂嵌套结构,#{...} 插值可能生成非法 CSS(比如 var(--x, (a: 1, b: 2))),此时应提前校验或拒绝传入。
真正容易被忽略的点:单位一致性与 IE 兼容边界
即使类型判断正确,降级仍可能失效。例如:
-
$gap: 1em是number类型,但插值后变成1em—— 这没问题; -
$gap: 12(漏写单位)也是number,插值后是12,CSS 会当作无单位数字被忽略(如margin: 12;非法); - IE11 及更早版本完全不支持
var(),所以所有var()行都会被跳过,**降级值必须是第一行**(即先写$fallback,再写var()); - 某些旧版 Safari 对
var()在@media内嵌套中的解析有 bug,若变量用于响应式断点,需额外测试。
结论很实在:类型判断只是起点,真正的降级健壮性取决于 fallback 值本身的合法性、单位完整性,以及你是否真的在目标浏览器里跑过验证。


















