Less不支持真正递归循环,而是通过带守卫的递归mixin在编译期展开生成静态CSS;需用when(@i>0)终止条件和(@i-1)显式递减,避免无限递归与作用域错误。

Less 本身不支持真正的递归循环,所谓“递归生成样式”其实是用 .loop() 混合(mixin)配合守卫(guards)和递减参数模拟的迭代行为——它不是运行时循环,而是编译期展开的静态规则生成。
为什么 Less 里写不出 for (let i = 1; i
Less 是预处理器,不是运行时脚本语言。它的“循环”本质是递归调用 mixin,靠守卫条件终止展开,最终输出的是固定数量的 CSS 规则,而非动态逻辑。
- 每次调用
.loop()都会生成一组新选择器或声明,编译后不可更改 - 若守卫没写对(比如漏了
@i > 0),会导致无限递归,Less 编译直接报错:Maximum call stack size exceeded - 生成的 CSS 条目数 = 初始参数值,比如
.loop(10)会硬编码 10 块样式,不能根据数据长度动态适配
正确写法:用带守卫的递归 mixin 生成层级类名
典型场景:生成 .indent-1 到 .indent-5,每级增加 20px 左侧内边距。
.indent-loop(@i: 5) when (@i > 0) {
.indent-@{i} {
padding-left: (@i * 20px);
}
// 递归调用下一级
.indent-loop((@i - 1));
}
<p>// 启动入口
.indent-loop();- 必须写
when (@i > 0)守卫,否则编译器无法判断何时停止 - 参数要显式递减,
(@i - 1)的括号不能省,否则 Less 会误解析为负号前缀 - 调用末尾的
.indent-loop();使用默认参数,等价于.indent-loop(5)
常见翻车点:变量作用域与计算时机
递归 mixin 中的变量不是“实时更新”的,每次调用都是独立作用域,所有计算在编译时完成。
立即学习“前端免费学习笔记(深入)”;
- 错误写法:
@padding: @i * 20px; .indent-@{i} { padding-left: @padding; }—— 看似没问题,但一旦混入其他计算(如叠加 margin),容易因作用域隔离导致值丢失 - 推荐把计算直接塞进属性值里,如
padding-left: (@i * 20px),避免中间变量 - 不要试图在递归中修改全局变量,Less 不支持跨 mixin 赋值,
@global-var: ...在递归里重复声明只会覆盖,不会累加
真正需要动态样式的场景(比如根据 JSON 数据生成类),Less 就力不从心了——这时候该换 PostCSS 插件或直接上 JS 生成 CSS-in-JS,别硬套递归 mixin。


















