Sass Maps, Loops, and Conditional Logic
Use maps, @each, @for, @while, and @if to generate utility classes, manage design tokens, and build data-driven stylesheet patterns.
Maps and Structured Design Tokens
A Sass map stores key-value pairs. Maps are useful for color palettes, spacing scales, typography levels, breakpoints, and component variants.
The sass:map module provides functions for retrieving values, checking keys, and producing updated maps. A map centralizes related data and makes repetitive generation possible.
Maps are especially valuable when a design system has several named variants. Instead of scattering individual values across multiple files, define a structured map and consume it through functions, mixins, or loops.
Map keys should be descriptive and stable. Treat changes to public token names as API changes when other components depend on them.
@use "sass:map";
$spacing: (
xs: 0.25rem,
sm: 0.5rem,
md: 1rem,
lg: 1.5rem,
xl: 2rem
);
.card {
padding: map.get($spacing, md);
}
.section {
margin-block: map.get($spacing, xl);
}$spacing map stores named spacing tokens. map.get() retrieves the value associated with a key.
Centralized maps reduce duplication and make it easier to review a design system's approved values. When a token is missing, consider adding explicit validation instead of silently producing incomplete CSS.Which Sass built-in module should you use to retrieve a value from a map?
Generate Styles with @each
The @each directive iterates over a list or map. It is ideal for generating classes from named tokens because each iteration exposes a value or a key-value pair.
For a map of button variants, a loop can generate a class for every supported variant. For a spacing map, a loop can generate utilities for approved spacing tokens.
Generated utilities should be intentionally scoped. A loop that creates hundreds of selectors may produce unnecessary CSS if only a few classes are used. Consider whether a small set of reusable component styles would be more appropriate.
$button-colors: (
primary: #5b5bd6,
success: #218838,
danger: #c62828
);
@each $name, $color in $button-colors {
.button--#{$name} {
background-color: $color;
color: white;
}
}.button--primary, .button--success, and .button--danger.Which directive is the natural choice for iterating through a map of named button variants?
Generate Repeated Utilities with @for
The @for directive iterates across a numeric range. It is useful when the generated selectors follow a predictable numeric pattern, such as a limited spacing scale or grid span utilities.
Sass supports through and to range syntax. through includes the ending number, whereas to stops before it.
For example, @for $i from 1 through 4 executes four iterations, while @for $i from 1 to 4 executes three.
Choose the smallest useful range. Large generated utility systems can increase CSS output and make class naming conventions harder to manage.
@for $i from 1 through 4 {
.grid-span-#{$i} {
grid-column: span $i;
}
}.grid-span-1, .grid-span-2, .grid-span-3, and .grid-span-4.
The generated declarations use CSS Grid's grid-column property. Ensure that the generated span values are meaningful within the grid layouts used by your application.How many iterations occur in `@for $i from 1 through 4`?
Conditional Logic with @if, @else, and @while
Sass supports conditional compilation through @if, @else if, and @else. These directives can select which declarations or rules are emitted based on Sass values.
The @while directive repeats a block while a condition remains true. Although useful in some algorithms, it is generally less readable than @each or @for for ordinary stylesheet generation.
Conditions are evaluated during compilation. They cannot respond directly to a user's browser interaction or a CSS custom property's runtime value.
Keep conditional stylesheet generation deterministic. Complicated conditional trees can make the final CSS difficult to reason about, especially when several conditions generate overlapping selectors.
Use @error for invalid configuration and @warn when an input is allowed but potentially problematic. These messages help catch design-system mistakes early.
@mixin surface-theme($theme) {
@if $theme == dark {
background: #171717;
color: #f5f5f5;
} @else if $theme == light {
background: #ffffff;
color: #222222;
} @else {
@error "Unsupported theme: #{$theme}";
}
}
.panel {
@include surface-theme(dark);
}@error stops compilation with a useful message.
Explicit validation is preferable to silently generating incorrect output when a function or mixin accepts a restricted set of values.When does Sass evaluate an `@if` condition?