scss函数不支持真正递归,仅能通过@for循环配合append()生成阶梯阴影;因编译期需确定值,无法延迟求值,递归调用会报错或栈溢出。

SCSS 函数无法真正递归生成阴影——它只支持 @for 循环,所谓“递归”是误传;你真正需要的是带衰减逻辑的 @for + append() 组合。
为什么 SCSS 里写不了真正的递归函数
SCSS 不支持函数调用自身(即无尾递归或栈式递归),@function 内部不能出现对自身的引用。网上所谓“递归 mixin”本质是用 @if + @else 守卫实现的模拟循环,底层仍是编译时展开,不是运行时调用。
常见错误现象:@return long-shadow($steps - 1) 直接报错 Undefined operation 或 Stack level too deep。
- SCSS 编译器在解析阶段就需确定所有值,无法延迟求值
- 所谓“递归 mixin”其实是用
.shadow-loop(@i)+when (@i > 0)守卫,靠多次展开模拟,但仍是静态展开,非函数式递归 - 真要动态层数,必须靠
@for $i from 1 through $steps—— 这才是可靠路径
@for 循环中控制透明度与偏移的衰减曲线
阶梯状阴影的核心不是层数多,而是每层的 alpha 和 offset 遵循可感知的衰减:太线性会发硬,太指数会断层。
实操建议:
- 偏移用线性:
$i * $step(如1px起步),保证物理距离均匀 - 透明度推荐反比衰减:
0.1 / $i,比pow(0.9, $i)更易控边缘浓度 - 避免用
random()—— 每次编译结果不同,UI 不可预测,CI/CD 构建不一致 - 若需深色模式适配,别在函数里写死
rgba(0,0,0,...),改用var(--shadow-color)并提前在:root中定义
示例片段:
@function stepped-shadow($steps: 12, $step: 1px) {
$shadows: ();
@for $i from 1 through $steps {
$alpha: 0.12 / $i;
$shadow: $i * $step $i * $step 0 0 rgba(0, 0, 0, $alpha);
$shadows: append($shadows, $shadow, comma);
}
@return $shadows;
}
生成值必须用 comma 拼接,且不能带引号
SCSS 函数返回的阴影列表,若没用 comma 参数调用 append(),最终输出会变成空格分隔,浏览器只认第一项;若用了引号包裹整个字符串(比如误用 "#{...}"),编译后变成带引号文本,CSS 解析失败。
常见错误现象:box-shadow: "0 1px 0 0 rgba(0,0,0,0.1), 0 2px 0 0 rgba(0,0,0,0.05)" → 浏览器静默忽略整条声明。
- 必须写:
append($shadows, $shadow, comma),不是append($shadows, "#{$shadow}") - 函数只返回值列表,
box-shadow属性必须在调用处赋值:box-shadow: stepped-shadow(10); - 不要在函数内拼
box-shadow:前缀,那是 CSS 层的事,不是 SCSS 函数职责
真机和高对比度模式下容易失效的两个隐藏点
即使 SCSS 编译完全正确,阶梯阴影在真实环境仍可能塌陷,原因不在代码,而在渲染链路。
-
overflow: hidden在父容器上会裁掉所有外溢阴影 —— 阶梯效果依赖逐层外延,一旦被截,只剩最内层,立体感全失 - iOS Safari 和部分安卓 WebView 在低电量或高对比度辅助模式下,会主动降级模糊半径 >8px 或层数 >5 的阴影,把 alpha 值压到 0.03 以下,导致视觉“消失”
- 检查方式:不用 DevTools 模拟,必须真机连接 Safari Web Inspector 实时看 computed
box-shadow值是否被浏览器重写
复杂点从来不在怎么写循环,而在于阶梯阴影是视觉、渲染、硬件策略共同作用的结果——SCSS 只管生成,剩下的得靠真机验证和 fallback 策略兜底。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











