<p>Less 没有原生 for 循环,需用带守卫条件的递归 mixin 模拟,如 .generate-mt(@n) when (@n > 0) { .mt-@{n} { margin-top: unit(@n, px); } .generate-mt(@n - 1); },调用时显式触发且受编译器递归深度限制。</p>

Less 里根本没有原生 for 循环
Less 不支持 for、while 或 each 这类编程语言中的循环语法。所谓“Less 循环”,其实是通过递归 mixin 模拟实现的——靠自己调用自己,配合计数器和终止条件来展开。如果你照着 JavaScript 思路去写 for (let i = 1; i ,会直接报错或啥也不输出。
用递归 mixin 实现数字范围类名生成
比如要生成 .mt-1 到 .mt-10,对应 margin-top: 1px 到 10px,就得定义一个带计数参数的 mixin,并在内部判断是否继续调用自身:
.generate-mt(@n) when (@n > 0) {
.mt-@{n} { margin-top: unit(@n, px); }
.generate-mt(@n - 1);
}
.generate-mt(10);关键点:
-
when (@n > 0)是 guard 条件,控制递归出口;没它就会无限循环编译失败 -
unit(@n, px)比直接写@{n}px更安全,避免拼出5pxpx这种错误 - 调用必须显式触发,如
.generate-mt(10),不会自动运行 - Less 编译器对递归深度有限制(通常 128 层),超了会报
Recursive call to mixin
生成带单位/倍数的响应式间距类(如 rem、em、倍数)
实际项目中,类名常需支持多种单位或比例(如 .p-2 是 0.5rem,.p-4 是 1rem)。这时递归 mixin 的参数不只是数字,还要处理映射逻辑:
立即学习“前端免费学习笔记(深入)”;
.gen-padding(@n) when (@n > 0) {
@val: (0.25 * @n) * 1rem;
.p-@{n} { padding: @val; }
.gen-padding(@n - 1);
}
.gen-padding(8);注意:
- 计算尽量放在变量赋值里(如
@val),别塞进属性值里,否则 Less 可能无法解析单位运算 - 如果想生成
.mb-md、.mb-lg这类语义名,就得改用 list 遍历方式(用extract()+ 索引递增),但本质仍是递归模拟 - 所有生成的类都会被静态展开,不会留下运行时逻辑——编译完就是纯 CSS,没副作用
为什么不用 JavaScript 插件或外部工具?
有人会想:既然 Less 不原生支持,干脆用 PostCSS 或写个脚本生成 CSS。这确实更灵活,但代价是构建链路变重、调试断点丢失、团队成员理解成本上升。Less 递归方案的真正价值在于:所有逻辑收敛在单个 .less 文件里,编辑器能跳转、能搜索、能局部注释,且不依赖额外构建步骤。不过也得承认:一旦需要条件分支(如“偶数加背景,奇数加边框”)或动态数据源(如从 JSON 读配置),就该果断切到 JS 驱动的方案了。


















