Control Flow & Guards
Use @if/@else, the if() function, and @error/@warn/@debug to make robust, self-checking Sass.
Generated CSS is only as trustworthy as the logic behind it. Sass gives you real control flow — @if/@else if/@else — plus three communication channels back to the developer: @debug, @warn and @error.
Statement @if vs the if() function
@if is a statement that decides which declarations to emit. The if($cond, $then, $else) function returns one of two values inline — reach for it inside a single property.
$dark: true;
.panel { color: if($dark, #eee, #111); } // inline choiceFail loudly at build time
| Directive | Effect |
|---|---|
@debug | Prints a value to the console; never ships |
@warn | Prints a warning + stack, keeps compiling |
@error | Stops the build with your message |
A library that @errors on a bad argument is a library that catches mistakes at compile time instead of shipping broken CSS.
Example
@use 'sass:map';
@use 'sass:meta';
$sizes: ('sm': 12px, 'md': 16px, 'lg': 20px);
@function size($name) {
// Guard 1: right type
@if meta.type-of($name) != 'string' {
@error 'size() expects a string, got #{meta.type-of($name)}.';
}
// Guard 2: known key
@if not map.has-key($sizes, $name) {
@error 'Unknown size "#{$name}". Try one of: #{map.keys($sizes)}.';
}
@return map.get($sizes, $name);
}
@mixin heading($level: 'md') {
font-size: size($level);
@if $level == 'lg' {
letter-spacing: -0.01em; // tighten only large headings
} @else {
letter-spacing: normal;
}
}
.h1 { @include heading('lg'); }
.h3 { @include heading; }
// .h1 { font-size: 20px; letter-spacing: -0.01em; }When to use it
- A mixin uses @error to immediately halt compilation with a clear message when a caller passes an invalid theme name, preventing silent wrong output.
- A developer uses the inline if() function for compact ternary expressions inside @each loops rather than verbose @if/@else blocks.
- A library uses @warn for deprecation notices so consumers see the message at build time without breaking their build — they can fix it at their own pace.
More examples
@error for hard validation
Uses @error to immediately stop compilation with a descriptive message when an invalid theme name is passed, preventing silent failures.
@use 'sass:map';
$themes: (light, dark, high-contrast);
@mixin apply-theme($name) {
@if not index($themes, $name) {
@error 'apply-theme: unknown theme #{$name}. Valid: #{$themes}';
}
// ... rest of mixin
}@warn for deprecation notices
Emits a deprecation warning at compile time while still delegating to the new mixin, giving callers time to migrate without breaking builds.
@mixin old-mixin($arg) {
@warn 'old-mixin is deprecated. Use new-mixin() instead.';
@include new-mixin($arg);
}
@mixin new-mixin($arg) {
color: $arg;
font-weight: 600;
}Compact inline if() in loops
Uses the inline if() function inside a loop to vary property values per iteration without verbose @if/@else blocks.
$items: apple, banana, cherry;
@each $item in $items {
.label-#{$item} {
font-weight: if($item == apple, 700, 400);
color: if($item == cherry, #dc2626, #111);
}
}
Discussion