Less 循环 #
Less 没有像 Sass 那样的 @for、@each、@while 循环语法,但可以通过递归 Mixin 实现循环功能。
递归 Mixin #
基本原理 #
递归 Mixin 是指在 Mixin 内部调用自身:
less
.loop(@n) when (@n > 0) {
.loop(@n - 1); // 递归调用
width: @n * 10px;
}
.box {
.loop(3);
}
编译结果:
css
.box {
width: 10px;
width: 20px;
width: 30px;
}
简单计数循环 #
less
.generate-columns(@n, @i: 1) when (@i =< @n) {
.col-@{i} {
width: percentage(@i / @n);
}
.generate-columns(@n, @i + 1); // 递归
}
.generate-columns(12);
编译结果:
css
.col-1 { width: 8.33333333%; }
.col-2 { width: 16.66666667%; }
.col-3 { width: 25%; }
.col-4 { width: 33.33333333%; }
.col-5 { width: 41.66666667%; }
.col-6 { width: 50%; }
.col-7 { width: 58.33333333%; }
.col-8 { width: 66.66666667%; }
.col-9 { width: 75%; }
.col-10 { width: 83.33333333%; }
.col-11 { width: 91.66666667%; }
.col-12 { width: 100%; }
循环模式 #
递增循环 #
less
.increment(@start, @end, @step: 1) when (@start =< @end) {
.item-@{start} {
width: @start * 10px;
}
.increment(@start + @step, @end, @step);
}
.increment(1, 5);
编译结果:
css
.item-1 { width: 10px; }
.item-2 { width: 20px; }
.item-3 { width: 30px; }
.item-4 { width: 40px; }
.item-5 { width: 50px; }
递减循环 #
less
.decrement(@n) when (@n > 0) {
.level-@{n} {
font-size: @n * 4px;
}
.decrement(@n - 1);
}
.decrement(6);
编译结果:
css
.level-6 { font-size: 24px; }
.level-5 { font-size: 20px; }
.level-4 { font-size: 16px; }
.level-3 { font-size: 12px; }
.level-2 { font-size: 8px; }
.level-1 { font-size: 4px; }
实用示例 #
网格系统 #
less
@columns: 12;
@gutter: 30px;
.generate-grid(@n, @i: 1) when (@i =< @n) {
.col-@{i} {
width: percentage(@i / @n);
}
.col-offset-@{i} {
margin-left: percentage(@i / @n);
}
.generate-grid(@n, @i + 1);
}
.generate-grid(@columns);
间距工具类 #
less
@spacing-unit: 8px;
@spacing-levels: 6;
.generate-spacing(@n, @i: 0) when (@i =< @n) {
.p-@{i} { padding: @i * @spacing-unit; }
.m-@{i} { margin: @i * @spacing-unit; }
.pt-@{i} { padding-top: @i * @spacing-unit; }
.pr-@{i} { padding-right: @i * @spacing-unit; }
.pb-@{i} { padding-bottom: @i * @spacing-unit; }
.pl-@{i} { padding-left: @i * @spacing-unit; }
.mt-@{i} { margin-top: @i * @spacing-unit; }
.mr-@{i} { margin-right: @i * @spacing-unit; }
.mb-@{i} { margin-bottom: @i * @spacing-unit; }
.ml-@{i} { margin-left: @i * @spacing-unit; }
.px-@{i} {
padding-left: @i * @spacing-unit;
padding-right: @i * @spacing-unit;
}
.py-@{i} {
padding-top: @i * @spacing-unit;
padding-bottom: @i * @spacing-unit;
}
.mx-@{i} {
margin-left: @i * @spacing-unit;
margin-right: @i * @spacing-unit;
}
.my-@{i} {
margin-top: @i * @spacing-unit;
margin-bottom: @i * @spacing-unit;
}
.generate-spacing(@n, @i + 1);
}
.generate-spacing(@spacing-levels);
字体大小 #
less
@font-sizes: 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 48;
.generate-font-size(@list, @i: 1) when (@i =< length(@list)) {
@size: extract(@list, @i);
.text-@{size} {
font-size: unit(@size, px);
}
.generate-font-size(@list, @i + 1);
}
.generate-font-size(@font-sizes);
编译结果:
css
.text-10 { font-size: 10px; }
.text-12 { font-size: 12px; }
.text-14 { font-size: 14px }
.text-16 { font-size: 16px; }
.text-18 { font-size: 18px; }
.text-20 { font-size: 20px; }
.text-24 { font-size: 24px; }
.text-28 { font-size: 28px; }
.text-32 { font-size: 32px; }
.text-36 { font-size: 36px; }
.text-48 { font-size: 48px; }
阴影层级 #
less
.generate-shadows(@n, @i: 1) when (@i =< @n) {
.shadow-@{i} {
box-shadow: 0 @i * 2px @i * 4px rgba(0, 0, 0, 0.1);
}
.generate-shadows(@n, @i + 1);
}
.generate-shadows(5);
编译结果:
css
.shadow-1 { box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); }
.shadow-2 { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); }
.shadow-3 { box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1); }
.shadow-4 { box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); }
.shadow-5 { box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); }
Z-Index 层级 #
less
@z-indexes: dropdown, sticky, fixed, modal, popover, tooltip;
@z-index-base: 1000;
.generate-z-index(@list, @i: 1) when (@i =< length(@list)) {
@name: extract(@list, @i);
.z-@{name} {
z-index: @z-index-base + @i * 100;
}
.generate-z-index(@list, @i + 1);
}
.generate-z-index(@z-indexes);
编译结果:
css
.z-dropdown { z-index: 1100; }
.z-sticky { z-index: 1200; }
.z-fixed { z-index: 1300; }
.z-modal { z-index: 1400; }
.z-popover { z-index: 1500; }
.z-tooltip { z-index: 1600; }
断点媒体查询 #
less
@breakpoints: {
sm: 576px;
md: 768px;
lg: 992px;
xl: 1200px;
xxl: 1400px;
};
.generate-breakpoints(@breakpoints);
使用 each 函数(Less 3.7+):
less
@breakpoints: {
sm: 576px;
md: 768px;
lg: 992px;
xl: 1200px;
};
each(@breakpoints, {
@media (min-width: @value) {
.container-@{key} {
max-width: @value;
}
}
});
动画关键帧 #
less
.generate-keyframes(@name, @from, @to) {
@keyframes @name {
from { @from(); }
to { @to(); }
}
}
.generate-keyframes(fade-in,
{ opacity: 0; },
{ opacity: 1; }
);
.fade-in {
animation: fade-in 0.3s ease;
}
颜色变体 #
less
@colors: primary, secondary, success, danger, warning, info;
@color-values: {
primary: #007bff;
secondary: #6c757d;
success: #28a745;
danger: #dc3545;
warning: #ffc107;
info: #17a2b8;
};
.generate-buttons(@list, @i: 1) when (@i =< length(@list)) {
@name: extract(@list, @i);
@color: @color-values[@name];
.btn-@{name} {
background: @color;
color: contrast(@color);
border-color: darken(@color, 5%);
&:hover {
background: darken(@color, 10%);
}
}
.btn-outline-@{name} {
background: transparent;
color: @color;
border: 1px solid @color;
&:hover {
background: @color;
color: contrast(@color);
}
}
.generate-buttons(@list, @i + 1);
}
.generate-buttons(@colors);
each 函数 #
Less 3.7+ 提供了 each 函数,简化循环操作:
遍历列表 #
less
@list: blue, red, green, yellow;
each(@list, {
.bg-@{value} {
background: @value;
}
});
编译结果:
css
.bg-blue { background: blue; }
.bg-red { background: red; }
.bg-green { background: green; }
.bg-yellow { background: yellow; }
遍历映射 #
less
@colors: {
primary: #007bff;
success: #28a745;
danger: #dc3545;
};
each(@colors, {
.text-@{key} {
color: @value;
}
.bg-@{key} {
background: @value;
}
});
编译结果:
css
.text-primary { color: #007bff; }
.bg-primary { background: #007bff; }
.text-success { color: #28a745; }
.bg-success { background: #28a745; }
.text-danger { color: #dc3545; }
.bg-danger { background: #dc3545; }
使用索引 #
less
@list: 10px, 20px, 30px;
each(@list, {
.spacing-@{index} {
padding: @value;
}
});
编译结果:
css
.spacing-1 { padding: 10px; }
.spacing-2 { padding: 20px; }
.spacing-3 { padding: 30px; }
最佳实践 #
使用有意义的变量名 #
less
// 推荐
.generate-columns(@column-count, @current: 1) when (@current =< @column-count) {
// ...
}
// 不推荐
.loop(@n, @i: 1) when (@i =< @n) {
// ...
}
限制循环深度 #
less
// 推荐:设置合理的上限
.generate-spacing(@n, @i: 0) when (@i =< @n) and (@i < 10) {
// ...
}
使用 each 简化代码 #
less
// 推荐:使用 each
each(@colors, {
.text-@{key} { color: @value; }
});
// 不推荐:复杂的递归
.generate-colors(@keys, @i: 1) when (@i =< length(@keys)) {
// ...
}
下一步 #
现在你已经掌握了循环,接下来学习 映射 来管理复杂数据结构!
最后更新:2026-03-28