Sass 條件迴圈 @while:什麼時候該用,什麼時候不該
@while 在條件為真時持續重複。與 @for 最大的差別是:次數不必事先知道,每一輪重新檢查條件。
基本寫法
$i: 6;
@while $i > 0 {
.col-#{$i} { width: $i * 100px; }
$i: $i - 1; // ← 這一行不能忘
}.col-6 { width: 600px; }
.col-5 { width: 500px; }
/* ... */
.col-1 { width: 100px; }三個必要元素:起始值、條件、更新。缺了最後一個就是無限迴圈。
迴圈裡不需要 !global
迴圈區塊不是獨立的作用範圍,$i: $i - 1; 會直接改到外層那個變數。這與寫在選取器或 混入 區塊裡不同,那裡的指派只影響區塊內。
無限迴圈沒有警告
$i: 1;
@while $i < 10 {
.a-#{$i} { width: $i * 10px; }
// 忘了 $i: $i + 1;
}編譯會直接卡住,不報錯、不逾時,看起來就像編譯器當掉。這是 @while 最主要的風險。
寫 @while 時先把更新那行寫好
養成「先寫 $i: $i + 1;,再回頭填內容」的習慣。或者,先想想是不是能改用 @for。
多數情況該用 @for
上面的遞減例子,@for 寫起來更短也更安全:
@for $i from 6 through 1 {
.col-#{$i} { width: $i * 100px; }
}能用 @for 表達的就用 @for。 它的次數由範圍決定,沒有忘記更新的可能。
@for | @while | |
|---|---|---|
| 次數 | 開始前就固定 | 每輪重新判斷 |
| 步進 | 固定為 1 | 任意運算 |
| 無限迴圈風險 | 沒有 | 有 |
| 可讀性 | 好 | 需要多看兩眼 |
真的適合它的場景
步進不是固定值 的時候,例如每一輪減半的刻度:
$size: 64px;
@while $size >= 4px {
.text-#{$size} { font-size: $size; }
$size: math.div($size, 2);
}.text-64px { font-size: 64px; }
.text-32px { font-size: 32px; }
.text-16px { font-size: 16px; }
.text-8px { font-size: 8px; }
.text-4px { font-size: 4px; }要用 @for 表達同樣的東西,得先自己算出「總共會有五階」,反而更繞。
另一個例子是累加到門檻為止:
$total: 0;
$step: 1;
@while $total < 100 {
.stack-#{$step} { padding-top: $total * 1px; }
$total: $total + $step * 10;
$step: $step + 1;
}別拿它做執行期的事
跟 @if 一樣,@while 在 編譯期 就跑完了。它不知道螢幕多寬、使用者選了什麼主題。需要隨狀態改變的值請交給 CSS 自訂屬性。
常見問題
@while 和 @for 差在哪?
@for 的次數在開始前就決定了,@while 則是每一輪重新檢查條件,次數可以由運算結果決定。能用 @for 表達的情況就該用 @for,它不會忘記更新計數。
忘記更新計數會怎樣?
條件永遠成立,編譯就會卡住不動,也不會有錯誤訊息,看起來像編譯器當掉。這是 @while 最主要的風險,也是不建議隨手使用它的原因。
什麼情況真的適合用 @while?
重複的次數要靠運算才知道的時候,例如每一輪把數值減半直到低於某個門檻。這種遞迴式的刻度用 @for 反而要先算出總次數,寫起來更繞。
迴圈裡改變數為什麼有效?
因為迴圈區塊不是獨立的作用範圍,在裡面對外層變數指派會直接改到它,不需要 !global。這與寫在選取器或混入區塊裡的行為不同。