Less中所谓“递归Mixin”实为编译期静态展开,非运行时递归;必须用when守卫+参数传递+显式终止条件(如when (@i > 0)),否则编译器无限展开报错Maximum call stack size exceeded。

为什么递归Mixin在Less中无法真正“递归”
Less的Mixin不支持运行时递归调用,.grid-col(12)里再调用.grid-col(11)会导致编译报错Recursive call to mixin。这不是语法写错了,而是Less解析器在编译期就拒绝展开无限嵌套——它连“有限递归”都禁掉,哪怕你写了终止条件。
所以所谓“递归Mixin”,本质是用循环展开替代递归逻辑,靠when守卫 + 多重定义 + 手动展开层级来模拟。常见做法是预设最大列数(比如12),然后为每个数字单独定义一个Mixin分支。
- 必须显式写出
.grid-col(1)到.grid-col(12)所有变体,不能靠一个Mixin自动推导全部 - 守卫条件
when (@n > 0)在Less里无效,因为编译器不执行数值比较逻辑,只做静态匹配 - 如果漏写某一层(比如跳过
.grid-col(7)),后续依赖它的类就不会生成
如何用守卫+多重定义安全生成col-1到col-12
核心是把每个列宽映射成独立Mixin,用when区分参数值,避免冲突。Less会按顺序匹配第一个满足守卫的定义,所以要把具体值放在前面,通用兜底放最后(虽然这里不需要兜底)。
.grid-col(@n) when (@n = 1) {
flex: 0 0 8.333333%;
}
.grid-col(@n) when (@n = 2) {
flex: 0 0 16.666667%;
}
.grid-col(@n) when (@n = 3) {
flex: 0 0 25%;
}
// ...一直写到 @n = 12
- 百分比计算必须手动写死,
100% / @n在守卫内不可用,Less不支持表达式求值 - 每个
when守卫里的等号是=不是==,后者会直接报错 - 不要试图用
@n * 8.333%这种写法——Less不会做算术,只会原样输出字符串
怎么让网格系统支持offset、push、pull等衍生类
Offset类本质是margin-left,但值必须和对应col宽度一致。不能复用.grid-col的计算逻辑,得另起一套守卫定义,否则编译会冲突或覆盖。
立即学习“前端免费学习笔记(深入)”;
.grid-offset(@n) when (@n = 1) {
margin-left: 8.333333%;
}
.grid-offset(@n) when (@n = 2) {
margin-left: 16.666667%;
}
// 同样要列到12
-
.grid-push和.grid-pull用left/right,但守卫结构完全一样,只是属性名不同 - 如果想支持
sm、md断点,就得给每个类加前缀,比如.grid-col-sm(@n),并重复整套守卫定义 - 所有衍生类必须和
.grid-col保持参数范围一致,否则.col-3 .col-sm-4这种组合会漏样式
实际使用时最容易忽略的兼容性细节
生成的CSS需要配合Flex容器才能生效,但Less本身不校验HTML结构。你写了.col-4,如果父元素没加display: flex,样式就完全不起作用。
- 必须配套提供
.grid-row类,且它得声明display: flex和flex-wrap: wrap,否则子项的flex值无效 - IE10/11对
flex: 0 0 calc(100% / 12)支持极差,所以百分比必须写死,不能用calc()动态算 - Less编译后CSS体积会随列数线性增长,12列系统光
.col-类就生成12条规则,加上offset/push/pull,轻松破百行——压缩前务必检查是否冗余
真正麻烦的不是写Mixin,而是保证每一条生成的CSS都落在正确的选择器下,且不被其他规则意外覆盖。比如.grid-offset(1)生成的margin-left,如果被重置CSS里的* { margin: 0 }干掉,就白写了。


















