Sass @else if Rule

Beginner
10 min read
Updated: Nov 2026
5 examples
Compiled CSS

Definition and Usage

The Sass @else if rule adds another tested branch after an @if. Its block runs only when every preceding condition was falsey and this expression is truthy.

Chain as many @else ifs as you need. The first truthy branch wins; later branches are skipped. End with a plain @else as the final fallback (soft default or @error).

Official pattern.

Per the Sass docs: write @else if <expr> { … } after @if to choose among several options (directions, tones, sizes) at compile time.

First match wins.

Order matters. Put specific tests first; use a final @else for everything else.

Truthiness.

Only false and null are falsey in Sass. Empty strings, empty lists, and 0 are truthy.

Syntax

SCSS
@use "sass:math";

@mixin triangle($size, $color, $direction) {
  height: 0;
  width: 0;
  border-color: transparent;
  border-style: solid;
  border-width: math.div($size, 2);

  @if $direction == up {
    border-bottom-color: $color;
  } @else if $direction == right {
    border-left-color: $color;
  } @else if $direction == down {
    border-top-color: $color;
  } @else if $direction == left {
    border-right-color: $color;
  } @else {
    @error "Unknown direction #{$direction}.";
  }
}

Pattern: @if → one or more @else if → optional final @else.

How It Chains

Where @else if fits in control flow:

FormMeaning
@if … @else if …Second (or later) tested branch
… @else if … @else { }Final untested fallback after the chain
Inside mixins / functionsMap keywords to styles or @return values
Final @else { @error … }Fail loudly on unknown API values

SCSS Examples

Ordered @if / @else if chains (often with a final @else). Open View Compiled CSS for verified output.

Example 1 — Directional Triangle

Official-style mixin: one CSS triangle, four directions, @error otherwise.

SCSS
@use "sass:math";

@mixin triangle($size, $color, $direction) {
  height: 0;
  width: 0;

  border-color: transparent;
  border-style: solid;
  border-width: math.div($size, 2);

  @if $direction == up {
    border-bottom-color: $color;
  } @else if $direction == right {
    border-left-color: $color;
  } @else if $direction == down {
    border-top-color: $color;
  } @else if $direction == left {
    border-right-color: $color;
  } @else {
    @error "Unknown direction #{$direction}.";
  }
}

.next {
  @include triangle(5px, black, right);
}

.up {
  @include triangle(8px, #036, up);
}

How It Works

  1. Share triangle setup above the chain.
  2. Test each direction with @if / @else if.
  3. Only the matching branch sets a colored border side.
  4. Invalid $direction hits @error in the final @else.

Example 2 — Heading Levels

Map a numeric level to type styles; soft default for anything else.

SCSS
@mixin heading($level: 1) {
  margin: 0 0 0.5rem;
  font-weight: 700;

  @if $level == 1 {
    font-size: 2rem;
    line-height: 1.2;
  } @else if $level == 2 {
    font-size: 1.5rem;
    line-height: 1.25;
  } @else if $level == 3 {
    font-size: 1.25rem;
    line-height: 1.3;
  } @else {
    font-size: 1rem;
    font-weight: 600;
  }
}

.h1 { @include heading(1); }
.h2 { @include heading(2); }
.h3 { @include heading(3); }
.h4 { @include heading(4); }

How It Works

  1. Levels 1–3 hit dedicated branches.
  2. Level 4 falls through to the final @else.
  3. Shared margin / weight sit outside the chain.
  4. First matching level wins — later tests are skipped.

Example 3 — Alert Tones

success / warning / danger, with info as the soft @else.

SCSS
@mixin alert($tone: info) {
  padding: 0.75rem 1rem;
  border-radius: 4px;
  border: 1px solid transparent;

  @if $tone == success {
    background: #e8f6ee;
    border-color: #2f9e64;
    color: #1b5e3b;
  } @else if $tone == warning {
    background: #fff6e5;
    border-color: #e6a700;
    color: #7a5b00;
  } @else if $tone == danger {
    background: #fdecee;
    border-color: #d64550;
    color: #8a1f28;
  } @else {
    background: #eef3ff;
    border-color: #3b6de0;
    color: #1f3f8f;
  }
}

.ok { @include alert(success); }
.warn { @include alert(warning); }
.bad { @include alert(danger); }
.info { @include alert(); }

How It Works

  1. Each tone is an exclusive branch.
  2. Default $tone: info lands in @else.
  3. No separate @else if info is required.
  4. Unknown tones also get the info look (soft fallback).

Example 4 — Spacer Scale Function

Return spacing tokens from a function chain; error on unknown sizes.

SCSS
@function spacer($size) {
  @if $size == xs {
    @return 0.25rem;
  } @else if $size == sm {
    @return 0.5rem;
  } @else if $size == md {
    @return 1rem;
  } @else if $size == lg {
    @return 1.5rem;
  } @else if $size == xl {
    @return 2rem;
  } @else {
    @error "Unknown spacer size `#{$size}`.";
  }
}

.stack {
  padding: spacer(md);
  gap: spacer(sm);
}

.hero {
  margin-bottom: spacer(xl);
}

How It Works

  1. Each call resolves to one @return.
  2. Keyword matches walk the @else if chain.
  3. Unknown names hit @error — no silent 0.
  4. Great for design tokens exposed as a small API.

Example 5 — Breakpoint Name → Padding

Reuse one mixin from several media queries with different keywords.

SCSS
@mixin breakpoint-padding($name) {
  @if $name == mobile {
    padding: 1rem;
  } @else if $name == tablet {
    padding: 1.5rem;
  } @else if $name == desktop {
    padding: 2rem;
  } @else {
    padding: 1rem;
  }
}

.shell {
  @include breakpoint-padding(mobile);
}

@media (min-width: 768px) {
  .shell {
    @include breakpoint-padding(tablet);
  }
}

@media (min-width: 1024px) {
  .shell {
    @include breakpoint-padding(desktop);
  }
}

How It Works

  1. One mixin owns the keyword → padding map.
  2. Call it inside each media query with a different name.
  3. Unknown names fall back to mobile padding via @else.
  4. Keeps breakpoint values in one place to edit.

Edge Cases & Pitfalls

Most @else if bugs are order, missing fallbacks, or overlapping separate @if blocks.

order

First match wins

Put specific tests before broad ones. Once a branch runs, later @else ifs are skipped.

fallback

End public APIs with @else

Use soft defaults when safe, or @error when unknown keywords would produce broken CSS.

chain

Prefer one chain over many @if

Separate @if blocks can all run. A single @if / @else if / @else chain keeps outcomes exclusive.

maps

Large keyword sets may prefer maps

Long chains work, but a map + map.get (with @error on missing keys) can scale cleaner.

Sass Support

@else if is a core Dart Sass control rule. It is not a browser CSS feature — support means your Sass compiler understands it.

ImplementationStatus
Dart SassSupported (recommended)
LibSass / node-sassSupported (deprecated toolchain)
Ruby SassSupported (end-of-life)
BrowsersN/A — only see compiled CSS

Prefer Dart Sass for new projects. SCSS and indented syntax both support @else if.

Key Takeaways

  • Chain: @if → @else if… → optional @else.
  • First match wins — later branches are skipped.
  • Fallback: soft default or @error in final @else.
  • Compile-time only — browsers see one winning branch.

One line: @else if is an ordered, exclusive test after @if.

Compile Notes

@else if never reaches the browser. Conceptual flow:

flow.txt
1. Evaluate @if — if truthy, run it and stop
2. Else evaluate each @else if in order — first truthy wins
3. If none matched, run the final @else (if present)
4. Final stylesheet contains only that branch’s CSS

Frequently Asked Questions

It adds another tested branch after an @if. The block runs only if every preceding condition was falsey and this @else if expression is truthy.
As many as you need. Sass evaluates them in order and runs only the first truthy block in the chain.
No. Once one block in the @if / @else if / @else chain succeeds, the rest are skipped.
@else if has its own condition. A plain @else has no condition—it is the final fallback when every prior test failed.
Often yes for public APIs—unknown keywords should fail loudly. Soft defaults in @else are fine when a safe fallback exists.
No. Like @if and @else, it is compile-time only. Browsers see styles from the winning branch only.

Next: Sass @each Rule

Loop lists and maps to generate repetitive CSS cleanly.

Sass @each Rule →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

8 people found this page helpful