The @each rule makes it easy to emit styles or evaluate code for each element of a list or each pair in a map. It's great for repetitive styles that only have a few variations between them, such as generating icon classes, theme colors, or breakpoint-specific rules.
It's usually written @each <variable> in <expression> { ... }, where the expression returns a list. The block is evaluated for each element of the list in turn, which is assigned to the given variable name.
Iterating a List
The simplest form loops over each element of a list and assigns it to a single variable.
The .scss file:
$sizes: 40px, 50px, 80px;
@each $size in $sizes {
.icon-#{$size} {
font-size: $size;
height: $size;
width: $size;
}
}The .css file:
.icon-40px {
font-size: 40px;
height: 40px;
width: 40px;
}
.icon-50px {
font-size: 50px;
height: 50px;
width: 50px;
}
.icon-80px {
font-size: 80px;
height: 80px;
width: 80px;
}Practical example: color palette
$colors: (
"blue": #4a90d9,
"green": #5cb85c,
"red": #d9534f,
"orange": #f0ad4e,
);
// ...or a plain list:
$names: blue, green, red, orange;
@each $name in $names {
.text-#{$name} {
color: map-get($colors, $name);
}
}With Maps
You can also use @each to iterate over every key/value pair in a map by writing it @each <variable>, <variable> in <expression> { ... }. The key is assigned to the first variable name, and the value (element) is assigned to the second.
The .scss file:
$icons: ("eye": "\f112", "start": "\f12e", "stop": "\f12f");
@each $name, $glyph in $icons {
.icon-#{$name}:before {
display: inline-block;
font-family: "Icon Font";
content: $glyph;
}
}The .css file:
.icon-eye:before {
display: inline-block;
font-family: "Icon Font";
content: "\f112";
}
.icon-start:before {
display: inline-block;
font-family: "Icon Font";
content: "\f12e";
}
.icon-stop:before {
display: inline-block;
font-family: "Icon Font";
content: "\f12f";
}Practical example: theme colors
$themes: (
"primary": #007bff,
"secondary": #6c757d,
"success": #28a745,
"danger": #dc3545,
"warning": #ffc107,
);
@each $name, $color in $themes {
.btn-#{$name} {
background-color: $color;
color: white;
&:hover {
background-color: darken($color, 10%);
}
}
}This generates a .btn-primary, .btn-secondary, .btn-success, etc., each with its own color and a darkened hover state, from a single concise block.
Practical example: breakpoints
$breakpoints: (
"sm": 576px,
"md": 768px,
"lg": 992px,
"xl": 1200px,
);
@each $name, $value in $breakpoints {
@media (min-width: $value) {
.container-#{$name} {
max-width: $value;
}
}
}Destructuring
If you have a list of lists, you can use @each to automatically assign variables to each of the values from the inner lists by writing it @each <variable...> in <expression> { ... }.
This is known as destructuring, since the variables match the structure of the inner lists. Each variable name is assigned to the value at the corresponding position in the list, or null if the list doesn't have enough values.
The .scss file:
$icons:
"eye" "\f112" 12px,
"start" "\f12e" 16px,
"stop" "\f12f" 10px;
@each $name, $glyph, $size in $icons {
.icon-#{$name}:before {
display: inline-block;
font-family: "Icon Font";
content: $glyph;
font-size: $size;
}
}The .css file:
@charset "UTF-8";
.icon-eye:before {
display: inline-block;
font-family: "Icon Font";
content: "\f112";
font-size: 12px;
}
.icon-start:before {
display: inline-block;
font-family: "Icon Font";
content: "\f12e";
font-size: 16px;
}
.icon-stop:before {
display: inline-block;
font-family: "Icon Font";
content: "\f12f";
font-size: 10px;
}Here each inner list ("eye" "\f112" 12px) is split across three variables: $name, $glyph, and $size.
Uneven inner lists
If an inner list has fewer values than variables, the extra variables are assigned null:
$data:
("a" 1px),
("b" 2px "extra"),
("c"); // only one element
@each $name, $value, $extra in $data {
@debug "#{$name} => value: #{$value}, extra: #{$extra}";
}
// a => value: 1px, extra: null
// b => value: 2px, extra: "extra"
// c => value: null, extra: nullWhy maps work with destructuring
SCSS vs. Sass Syntax
@each works in both syntaxes. In the indented .sass syntax, the block is indicated by indentation (no braces, no semicolons):
$sizes: 40px, 50px, 80px
@each $size in $sizes
.icon-#{$size}
font-size: $size
height: $size
width: $sizeCompiles to the same CSS as the SCSS version.
Using @each with Index: meta.load-css / list.index
@each does not give you the loop index directly. If you need an index (for example, for nth-child selectors), use the list.index() function alongside it, or fall back to @for:
@use "sass:list";
$columns: ("one", "two", "three", "four");
@each $name in $columns {
$i: list.index($columns, $name);
.col-#{$name} {
order: $i;
}
}Compiles to:
.col-one { order: 1; }
.col-two { order: 2; }
.col-three { order: 3; }
.col-four { order: 4; }@each vs @for
| Feature | @each |
@for |
|---|---|---|
| Iterates over | Elements of a list or pairs in a map | A range of numbers |
| Provides | The current element (and/or key) | A counter variable ($i) |
| Best for | Named collections, key/value data | Numeric ranges, repeating a fixed count |
Use @each when your data is a named collection (icons, theme colors, breakpoints); use @for when you need a numeric counter (e.g., generating 12 grid columns by index).
Summary
| Form | Syntax | Assigns |
|---|---|---|
| List | @each $var in $list { ... } |
One element per iteration |
| Map | @each $key, $val in $map { ... } |
Key + value per iteration |
| Destructuring | @each $a, $b, $c in $list-of-lists { ... } |
Positional values from each inner list (missing → null) |
Key points to remember:
@eachloops over lists and maps, not numeric ranges (use@forfor those).- Use interpolation (
#{...}) to embed variables into selectors or property names. - Maps are just lists of key/value pairs, so map iteration is a special case of destructuring.
- Missing values in destructuring are filled with
null, not an error. - Need an index? Use
list.index()or switch to@for.