Less原生不支持循环语法,所谓“loop”是社区基于递归mixin实现的;需手动定义带终止条件的递归mixin(如.col-loop),通过参数传递计数器,避免变量赋值和超深递归。

Less里没有loop语法,别被误导了
Less本身不支持类似Sass的@for或@each循环,所谓“loop”是社区封装的mixin(比如.loop()),本质是递归调用。直接写loop(12)会报错:ReferenceError: loop is not defined,因为Less原生根本不认识这个函数。
常见错误是复制粘贴网上不加验证的“Less循环代码”,结果编译失败,或者生成的CSS列类名漏掉、重复、顺序错乱——根本原因是没理解递归终止条件或变量作用域。
- 必须手动引入或定义递归mixin,不能直接用
loop - 递归深度默认受限(Less 4.x约256层),列数超200就可能爆栈
- 变量在递归中不可变,得用参数传递当前计数,不能靠
@i: @i + 1
用递归mixin实现12列网格的.col-1到.col-12
核心是定义一个带计数器参数的mixin,每次生成一类样式后调用自身,直到计数器超限:
.col-loop(@n, @i: 1) when (@i =< @n) {
.col-@{i} { width: percentage(@i / 12); }
.col-offset-@{i} { margin-left: percentage(@i / 12); }
.col-loop(@n, (@i + 1));
}
.col-loop(12);这段代码会生成.col-1~.col-12共12组规则。注意三点:
立即学习“前端免费学习笔记(深入)”;
when (@i = 是守卫条件,控制递归出口,漏写会导致无限循环编译卡死-
@{i}是变量插值,不是@i——后者只是数字,无法拼进类名 - 除法用
percentage()而非@i * 8.333%,避免浮点误差累积(比如1/12算出来是8.3333333%,手写易错)
为什么不用for而坚持递归?兼容性和可维护性问题
Less 3.8+虽支持for语法糖(需插件),但实际项目里基本不用:它依赖less-plugin-for,Webpack/Vite等构建工具要额外配loader,CI环境容易因插件缺失导致编译失败;而纯递归mixin零依赖,所有Less版本都跑得通。
更大的坑在维护上:递归逻辑一旦写错(比如把(@i + 1)写成@i + 1),Less不会报语法错误,而是静默生成错误的CSS(例如.col-11+1这种非法类名),排查成本远高于写错for循环。
- 团队协作时,递归mixin比插件方案更容易审查和调试
- 如果真要动态列数(比如响应式分
sm-6/md-4),建议拆成多个独立mixin,别硬塞进一个深层递归里 - 生成超过24列时,务必测下编译耗时——递归层数翻倍,Less解析时间非线性增长
生成的CSS体积和BEM命名冲突风险
12列网格光.col-N就输出12条规则,加上offset、push、pull,轻松破50行。如果再加断点(@media (min-width: 768px)套一层),体积直接翻3倍。更麻烦的是命名污染:.col-6可能和第三方UI库的.col-6冲突,尤其用@import混入多个Less文件时。
- 用
namespace包裹(如#grid { .col-loop(12); }),生成的CSS会带前缀,避免全局污染 - 生产环境务必开启Less压缩(
clean-css),否则冗余空格和换行会让CSS膨胀20%+ - 如果项目已用Tailwind,别硬套Less网格——它的
grid-cols-12等工具类更轻量,且支持JIT按需生成
递归mixin看着简单,但计数器管理、插值写法、守卫条件这三处,任一写错都会让生成结果完全不可控。与其反复调试,不如先用console.log式注释(// .col-@{i} generated)确认每轮输出是否符合预期。


















