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 choice

Fail loudly at build time

DirectiveEffect
@debugPrints a value to the console; never ships
@warnPrints a warning + stack, keeps compiling
@errorStops 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

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

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

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

Example · css
$items: apple, banana, cherry;

@each $item in $items {
  .label-#{$item} {
    font-weight: if($item == apple, 700, 400);
    color:       if($item == cherry, #dc2626, #111);
  }
}

Discussion

  • Be the first to comment on this lesson.