SCSS函数不支持递归,因编译期需确定所有值,无法延迟执行;唯一可靠方式是用@for $i from 1 through $steps循环替代,如生成阶梯阴影或栅格类。

SCSS 里不能写真正递归的函数——编译器不支持函数调用自身,任何尝试如 @return grid-classes($n - 1) 都会报 Stack level too deep 或 Undefined operation。
你真正需要的,是用 @for 循环替代“递归思维”,它更稳定、可控,且符合 SCSS 编译期求值的本质。
为什么 SCSS 函数不能递归
SCSS 编译阶段必须确定所有值,无法延迟执行或运行时调用。所谓“递归函数”在 SCSS 中不存在,网上示例基本是误把 mixin 守卫逻辑当成函数递归,或是直接抄 Sass 语法导致编译失败。
-
@function内部引用自身会触发栈溢出,不是语法警告,而是硬性限制 - 试图用
@if+@return模拟递归,仍会在解析阶段展开全部分支,体积爆炸且不可维护 - 想动态控制层数?只能靠
@for $i from 1 through $steps—— 这才是唯一可靠路径
@for 是生成栅格类的正确起点
从 .col-1 到 .col-12,必须用 through(不是 to),否则漏掉终点类:
@for $i from 1 through 12 {
.col-#{$i} {
flex: 0 0 percentage($i / 12.0);
max-width: percentage($i / 12.0);
}
}
-
percentage($i / 12.0)的.0不可省:没有它,1 / 12会被截断为0,结果全是0% - 别用
calc(100% / 12 * #{$i}):浏览器小数截断可能导致 12 列总宽不足 100%,换行错位 - 如果列数要改(比如切到 24 列),只改
$grid-columns: 24和through 24即可,其余自动适配
响应式栅格必须外层 @each、内层 @for
断点与列数交叉组合极易产出冗余 CSS。正确结构是:每个断点只包裹自己需要的列类,而不是让每个 .col-6 都重复声明所有媒体查询:
$breakpoints: (sm: 576px, md: 768px, lg: 992px);
<p>@each $name, $width in $breakpoints {
@media (min-width: $width) {
@for $i from 1 through 12 {
.col-#{$name}-#{$i} {
flex: 0 0 percentage($i / 12.0);
}
}
}
}</p>
-
@each拿到的是键值对:$name是sm,$width是576px;拼类名必须用#{$name},不是#{$width} - 别把
@for放在外层:那样每个列数都会生成全部断点,CSS 体积翻 3 倍以上 - 如果某断点下不需要响应式(如移动端强制单列),直接跳过该
@each分支,不写@media
容易被忽略的 subgrid 继承前提
如果你后续要用 subgrid,这些类名只是表皮,真正起效靠的是父容器轨道定义是否精确传递:
- 父级必须显式声明
grid-template-columns(不能只靠repeat(auto-fit, ...)) - 子容器设
grid-template-columns: subgrid前,必须确保它是父 grid 的**直接子元素** - 若中间插了非 grid 容器(如
<div class="card"> 但没设 <code>display: grid),subgrid 映射链就断了,样式无效 - SCSS 只负责写得清楚,最终生效与否,取决于 HTML 结构和父级 grid 定义是否严格对齐











