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

Example · css
@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.

Example · css
@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.

Example · css
$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.

Example · css
@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

  • Be the first to comment on this lesson.