Generating Utilities with Loops
Drive @each, @for and @while from maps to emit whole utility families from a few lines.
Loops are where Sass stops feeling like CSS and starts feeling like a build tool. Point @each at a map of tokens and you can generate an entire utility family — spacing, colours, display helpers — from a single source of truth.
@each over a map
$space: (0: 0, 1: 4px, 2: 8px, 3: 16px);
@each $key, $val in $space {
.p-#{$key} { padding: $val; }
}
// .p-0{padding:0} .p-1{padding:4px} ...Which loop, when?
@each— you have a list/map and want one rule per item. The workhorse.@for— you need a numeric range, e.g. a 12-column grid.@while— rare; use it only when the stopping condition is not a simple count.
Interpolation #{} is what lets you build selector names and, in the example panel, whole CSS custom-property names on the fly.
Example
@use 'sass:map';
$spacers: (0: 0, 1: .25rem, 2: .5rem, 3: 1rem, 4: 2rem);
$sides: ('t': 'top', 'r': 'right', 'b': 'bottom', 'l': 'left');
$props: ('m': 'margin', 'p': 'padding');
// Nested @each -> a full margin/padding utility matrix
@each $pKey, $pName in $props {
@each $sKey, $sName in $sides {
@each $step, $val in $spacers {
.#{$pKey}#{$sKey}-#{$step} {
#{$pName}-#{$sName}: $val;
}
}
}
}
// .mt-3 { margin-top: 1rem } ... .pl-1 { padding-left: .25rem } ...
// @for -> a responsive 12-column grid
@for $i from 1 through 12 {
.col-#{$i} { flex: 0 0 percentage(math.div($i, 12)); }
}When to use it
- A utility CSS framework generates all 400+ spacing, color, and display classes from a handful of Sass maps using nested @each loops.
- A developer drives a single @for loop from a spacing map to emit margin and padding utilities for every scale step, cutting 300 lines to 10.
- A team uses @each over a breakpoint map as the outer loop and a property map as the inner loop to generate responsive utility variants.
More examples
Spacing utilities from a map
Two nested @each loops over a spacing scale and a property alias map generate all margin/padding utility classes in one block.
@use 'sass:map';
$space: (0: 0, 1: 0.25rem, 2: 0.5rem, 4: 1rem, 8: 2rem, 16: 4rem);
$props: (m: margin, p: padding, mt: margin-top, mb: margin-bottom);
@each $abbr, $prop in $props {
@each $key, $val in $space {
.#{$abbr}-#{$key} { #{$prop}: $val; }
}
}Responsive utilities with breakpoints
Generates responsive display utilities like .md:d-flex for every breakpoint and display value combination using two nested loops.
$bps: (sm: 640px, md: 768px, lg: 1024px);
$displays: block, flex, grid, none;
@each $bp, $w in $bps {
@media (min-width: $w) {
@each $d in $displays {
.#{$bp}\:d-#{$d} { display: $d; }
}
}
}@for-driven column grid
A @for loop generates both span and offset column classes for a 12-column grid, producing 24 classes from 4 lines of Sass.
@use 'sass:math';
$cols: 12;
.grid { display: grid; grid-template-columns: repeat($cols, 1fr); }
@for $i from 1 through $cols {
.col-#{$i} { grid-column: span $i; }
.col-off-#{$i} { grid-column-start: $i + 1; }
}
Discussion