Control Directives
Sass isn't just a way to organize CSS — it has real programming constructs. @each and @for generate repetitive CSS from a list or a range instead of you typing every variation out by hand, and @if/@else lets a mixin branch on a condition.
@each: looping over a list or map
A Sass map pairs keys with values, and @each can loop over one to generate a rule per entry:
$theme-colors: (
primary: #1b6ec2,
danger: #dc3545,
success: #28a745
);
@each $name, $color in $theme-colors {
.text-#{$name} {
color: $color;
}
}
.text-primary {
color: #1b6ec2;
}
.text-danger {
color: #dc3545;
}
.text-success {
color: #28a745;
}#{$name} is interpolation — it drops the variable's value directly into the selector name. Without the #{}, Sass would try to treat $name as part of a plain identifier and fail; interpolation is required any time a variable needs to appear inside a selector or property name rather than as a value.
@for: looping over a numeric range
@use 'sass:math';
@for $i from 1 through 4 {
.col-#{$i} {
width: math.div(100%, 4) * $i;
}
}
.col-1 {
width: 25%;
}
.col-2 {
width: 50%;
}
.col-3 {
width: 75%;
}
.col-4 {
width: 100%;
}from 1 through 4 includes both endpoints, running the loop body 4 times with $i set to 1, 2, 3, then 4 in turn — a four-column grid system defined in four lines instead of four separate hand-written rules.
@if / @else
Inside a mixin or function, @if and @else let the generated CSS branch based on a condition — here, picking readable text color depending on how light or dark a background color is:
@mixin readable-text($background) {
@if lightness($background) > 50% {
color: black;
} @else {
color: white;
}
}
.badge-light {
background: #f4f6fa;
@include readable-text(#f4f6fa);
}
.badge-dark {
background: #10131c;
@include readable-text(#10131c);
}
.badge-light {
background: #f4f6fa;
color: black;
}
.badge-dark {
background: #10131c;
color: white;
}lightness() is another built-in color function — it returns a color's lightness as a percentage, which the @if then compares against 50% to decide which branch runs for each call.
& parent selector, splitting code across partials with @use/@forward, reusable mixins with arguments and @content, built-in color/math functions, sharing styles with @extend and placeholder selectors, and generating CSS programmatically with @each, @for, and @if/@else. From here, the natural next step is picking a real project — even converting one of your own existing CSS files to SCSS is a solid way to see where these tools actually save you time.