Episode 1 — Fundamentals / 1.7 — Working With SASS
1.7.h — Control Directives
In one sentence: SCSS control directives —
@if,@for,@each, and@while— let you generate CSS programmatically, replacing hundreds of hand-written utility classes, grid columns, or color variants with a few lines of logic.
Navigation: ← 1.7.g — Functions & Operators · 1.7.i — Color Functions →
1. @if / @else if / @else
Basic conditional
@mixin theme($mode) {
@if $mode == 'dark' {
background: #1e293b;
color: #f1f5f9;
} @else if $mode == 'dim' {
background: #334155;
color: #e2e8f0;
} @else {
background: #ffffff;
color: #1e293b;
}
}
body { @include theme('dark'); }
Conditionals inside functions
@function text-contrast($bg) {
@if lightness($bg) > 50% {
@return #1e293b;
} @else {
@return #f8fafc;
}
}
.banner {
$bg: #3b82f6;
background: $bg;
color: text-contrast($bg); // returns light text for dark blue
}
2. @for loop
Two flavors:
| Syntax | Range | Iteration |
|---|---|---|
@for $i from 1 through 5 | 1, 2, 3, 4, 5 | Inclusive of end |
@for $i from 1 to 5 | 1, 2, 3, 4 | Exclusive of end |
Generate spacing utilities
@for $i from 1 through 8 {
.mt-#{$i} {
margin-top: $i * 0.25rem;
}
}
Compiled CSS:
.mt-1 { margin-top: 0.25rem; }
.mt-2 { margin-top: 0.5rem; }
.mt-3 { margin-top: 0.75rem; }
/* … */
.mt-8 { margin-top: 2rem; }
Generate grid columns
@use 'sass:math';
$columns: 12;
@for $i from 1 through $columns {
.col-#{$i} {
width: math.div(100%, $columns) * $i;
}
}
3. @each — iterating lists and maps
Iterate a list
$sizes: 'sm', 'md', 'lg', 'xl';
@each $size in $sizes {
.text-#{$size} {
font-size: var(--text-#{$size});
}
}
Iterate a map
$colors: (
'primary': #3b82f6,
'secondary': #64748b,
'success': #22c55e,
'danger': #ef4444,
'warning': #f59e0b,
);
@each $name, $color in $colors {
.bg-#{$name} {
background-color: $color;
}
.text-#{$name} {
color: $color;
}
}
Compiled CSS:
.bg-primary { background-color: #3b82f6; }
.text-primary { color: #3b82f6; }
.bg-secondary { background-color: #64748b; }
.text-secondary { color: #64748b; }
/* … and so on */
Destructuring lists of lists
$icons: (
('home', '\e900'),
('search', '\e901'),
('user', '\e902'),
);
@each $name, $code in $icons {
.icon-#{$name}::before {
content: $code;
font-family: 'Icons';
}
}
4. @while loop
$i: 6;
@while $i > 0 {
.width-#{$i} {
width: $i * 100px;
}
$i: $i - 1;
}
@while is rarely used — @for and @each cover nearly all cases. Use @while only when the iteration count depends on a computed condition.
Danger: An infinite @while loop will hang the compiler. Always ensure the condition changes and will eventually become false.
5. Practical example — generating a full color palette
@use 'sass:color';
$base-colors: (
'blue': #3b82f6,
'green': #22c55e,
'red': #ef4444,
);
$shades: (100, 200, 300, 400, 500, 600, 700, 800, 900);
@each $name, $base in $base-colors {
@each $shade in $shades {
$lightness-adjust: ($shade - 500) * -0.1%;
.color-#{$name}-#{$shade} {
color: color.adjust($base, $lightness: $lightness-adjust);
}
}
}
This generates 27 classes (3 colors × 9 shades) from 10 lines of SCSS.
6. Practical example — responsive grid system
@use 'sass:math';
$breakpoints: ('sm': 640px, 'md': 768px, 'lg': 1024px);
$columns: 12;
@each $bp-name, $bp-value in $breakpoints {
@media (min-width: $bp-value) {
@for $i from 1 through $columns {
.col-#{$bp-name}-#{$i} {
width: math.div(100%, $columns) * $i;
}
}
}
}
Output: .col-sm-1 through .col-sm-12, .col-md-1 through .col-md-12, .col-lg-1 through .col-lg-12 — 36 classes from ~10 lines.
7. Best practices
| Practice | Why |
|---|---|
Prefer @each over @for when iterating named items | More readable — the loop variable has meaning |
| Avoid deeply nested loops | Output CSS can explode in size — always check compiled output |
| Check compiled CSS size | Loops can generate thousands of rules; only generate what you need |
| Use maps for configuration | Maps + @each = data-driven CSS generation |
Guard @while with a limit | Prevent infinite loops during development |
8. Key takeaways
@iflets you conditionally emit CSS — commonly used in mixins and functions.@forgenerates numbered sequences — perfect for grids, spacing scales, and index-based classes.@eachiterates lists and maps — the most versatile loop for named data.@whileis a last resort — use only when the stop condition is computed dynamically.- Control directives are compile-time — the browser receives flat CSS with no loops or conditions.
Explain-It Challenge
Explain without notes:
- What is the difference between
@for $i from 1 through 5and@for $i from 1 to 5? - How would you generate
.bg-primary,.bg-secondary,.bg-dangerclasses from a SCSS map? - Why might generating too many classes with loops be a problem for production CSS?
Navigation: ← 1.7.g — Functions & Operators · 1.7.i — Color Functions →