Skip to content

Sass 走訪迴圈 @each:批次產生類別

Sass 走訪迴圈 @each 的用法

@each 走訪一組資料,每一項執行一次區塊內容。它是 Sass 裡最常用的迴圈,主題色、間距刻度、斷點、圖示,這些「一組資料對應一組樣式」的需求都靠它。

走訪 list

scss
$sides: top, right, bottom, left;

@each $side in $sides {
  .m-#{$side} {
    margin-#{$side}: 16px;
  }
}
css
.m-top { margin-top: 16px; }
.m-right { margin-right: 16px; }
.m-bottom { margin-bottom: 16px; }
.m-left { margin-left: 16px; }

變數要放進選取器與屬性名,必須用 插值

走訪 map

寫兩個變數就能同時拿到鍵與值:

scss
$theme: (
  primary: #2965f1,
  danger: #e03131,
  success: #2f9e44,
);

@each $name, $color in $theme {
  .text-#{$name} { color: $color; }
  .bg-#{$name}   { background: $color; }
}
css
.text-primary { color: #2965f1; }
.bg-primary { background: #2965f1; }
.text-danger { color: #e03131; }
.bg-danger { background: #e03131; }
.text-success { color: #2f9e44; }
.bg-success { background: #2f9e44; }

一組資料換來六條規則,之後新增一個顏色只要在 map 加一行。

解構多個值

list 裡放 list 的話,可以一次取出多個欄位:

scss
$buttons: (
  (primary, #2965f1, #fff),
  (danger,  #e03131, #fff),
  (warning, #f59f00, #1a1a1a),
);

@each $name, $bg, $fg in $buttons {
  .btn-#{$name} {
    background: $bg;
    color: $fg;
  }
}

欄位一多就改用 map

三欄以上時,(name: primary, bg: #2965f1, fg: #fff) 這種 map 比位置對應好讀,也不怕漏一欄就整組錯位。取值用 map.get()

巢狀走訪

主題乘上狀態,交叉產生:

scss
@use "sass:map";

$themes: (
  light: (bg: #fff, text: #333),
  dark:  (bg: #1a1a1a, text: #f5f5f5),
);

@each $name, $tokens in $themes {
  [data-theme="#{$name}"] {
    @each $key, $value in $tokens {
      --#{$key}: #{$value};
    }
  }
}
css
[data-theme="light"] { --bg: #fff; --text: #333; }
[data-theme="dark"] { --bg: #1a1a1a; --text: #f5f5f5; }

這正是產生 多主題 CSS 自訂屬性 的標準寫法。

搭配混入

迴圈裡呼叫 混入 也很常見:

scss
@each $bp in (sm, md, lg) {
  @include respond-to($bp) {
    .container-#{$bp} { max-width: 100%; }
  }
}

小心組合爆炸

scss
// ⚠️ 4 個屬性 × 4 個方向 × 10 個尺寸 = 160 條規則
@each $prop in (margin, padding) {
  @each $side in (top, right, bottom, left) {
    @each $i in (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) {
      .#{$prop}-#{$side}-#{$i} { #{$prop}-#{$side}: $i * 4px; }
    }
  }
}

三層巢狀迴圈很容易產出上千條你永遠用不到的規則。

只產生真的會用到的組合

把尺寸刻度縮到六階、方向只留 x 與 y 軸,數量立刻降一個量級。或者交給能自動移除未使用樣式的工具處理,見 工具類別效能與產出品質

常見問題

@each 可以同時取出鍵和值嗎?

可以。走訪 map 時寫兩個變數,第一個接鍵、第二個接值。走訪由多個 list 組成的 list 時也能用同樣的方式一次解構出多個欄位。

迴圈裡怎麼把變數變成類別名稱?

插值。變數不能直接出現在選取器的位置,要寫成 .text-#{$name} 這種形式,編譯時就會展開成一條條實際的類別。

產生太多類別會不會讓 CSS 變肥?

會,而且很容易失控。三個維度各十個值交叉相乘就是一千條規則。只產生專案真的會用到的組合,或改用能自動移除未使用樣式的工具。

@each 和 @for 該用哪個?

有一組現成的資料要逐項處理就用 @each;需要的是一連串連續的數字,例如柵格的一到十二欄,就用 @for。多數情況 @each 的可讀性比較好。

延伸閱讀