Sass @if Rule

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

Definition and Usage

The Sass @if rule is written @if <expression> { … } and controls whether its block gets evaluated — including emitting any styles as CSS.

The expression usually returns true or false. If it is truthy, the block runs; if it is falsey, the block is skipped. This page focuses on single-branch @if. Two-way fallbacks use @else; multi-branch chains use @else if.

Official pattern.

Per the Sass docs: use @if inside mixins for optional knobs (for example $circle) so styles compile only when needed.

Compile-time only.

Browsers never see @if — only CSS from blocks that ran.

Truthiness surprise.

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

Syntax

SCSS
@use "sass:math";

@mixin avatar($size, $circle: false) {
  width: $size;
  height: $size;

  @if $circle {
    border-radius: math.div($size, 2);
  }
}

.square-av {
  @include avatar(100px, $circle: false);
}

.circle-av {
  @include avatar(100px, $circle: true);
}

Pattern: evaluate a condition → emit styles only when it is truthy.

How It Works

Core @if shapes:

FormMeaning
@if $flag { … }Run the block when the value is truthy
@if $theme == dark { … }Compare values, then branch
@if $a and $b { … }Combine with and / or / not
@if string.index($s, " ") { … }null means missing (falsey); a number means found

SCSS Examples

Single-branch @if (no @else chains). Open View Compiled CSS for verified output.

Example 1 — Optional Mixin Styles

Official-style avatar: add a radius only when $circle is true.

SCSS
@use "sass:math";

@mixin avatar($size, $circle: false) {
  width: $size;
  height: $size;

  @if $circle {
    border-radius: math.div($size, 2);
  }
}

.square-av {
  @include avatar(100px, $circle: false);
}

.circle-av {
  @include avatar(100px, $circle: true);
}

How It Works

  1. Both calls get width and height from the mixin.
  2. @if $circle runs only when the flag is truthy.
  3. Square avatar skips the radius block entirely.
  4. Circle avatar emits border-radius: 50px.

Example 2 — Feature Flags

Config variables gate declarations or whole rules.

SCSS
$enable-shadows: true;
$is-rtl: false;

.card {
  padding: 1rem;

  @if $enable-shadows {
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
  }

  @if $is-rtl {
    margin-right: auto;
  }
}

@if $enable-shadows {
  .floating {
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
  }
}

How It Works

  1. Shadows are on, so those blocks emit CSS.
  2. $is-rtl is false, so no RTL margin appears.
  3. Top-level @if can gate entire selectors.
  4. Flip the flags and recompile to change the stylesheet.

Example 3 — null From string.index

Treat a missing substring as falsey without writing != null.

SCSS
@use "sass:string";

@mixin spaced-label($text) {
  content: $text;

  @if string.index($text, " ") {
    letter-spacing: 0.04em;
  }
}

.one-word {
  &::before {
    @include spaced-label("Hello");
  }
}

.two-words {
  &::before {
    @include spaced-label("Hello World");
  }
}

How It Works

  1. No space → string.index returns null (falsey).
  2. A space returns an index number (truthy).
  3. Letter-spacing emits only for the two-word label.
  4. Official tip: use null returns as “missing” checks.

Example 4 — and / or / not

Combine comparisons inside a single @if.

SCSS
$theme: dark;
$density: compact;

.panel {
  padding: 1rem;

  @if $theme == dark and $density == compact {
    background: #111;
    color: #eee;
    padding: 0.5rem;
  }

  @if $theme == light or $theme == dark {
    border: 1px solid currentColor;
  }

  @if not ($theme == light) {
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
  }
}

How It Works

  1. and requires both dark and compact.
  2. or accepts either light or dark.
  3. not inverts a comparison.
  4. Later padding overrides the earlier one in the same rule.

Example 5 — Surprising Truthy Values

Empty strings, 0, and empty lists are truthy; false and null are not.

SCSS
@mixin truth-demo($value, $label) {
  @if $value {
    --#{$label}: on;
  }
}

.checks {
  @include truth-demo("", "empty-string");
  @include truth-demo(0, "zero");
  @include truth-demo((), "empty-list");
  @include truth-demo(false, "false");
  @include truth-demo(null, "null");
}

How It Works

  1. Three truthy calls emit custom properties.
  2. false and null skip their blocks.
  3. Unlike JavaScript, 0 and "" succeed here.
  4. Prefer explicit comparisons when zero should mean “off.”

Edge Cases & Pitfalls

Most @if bugs are truthiness assumptions or expecting runtime behavior.

truthy

0 and "" are truthy

Only false and null fail. Write @if $n != 0 when zero should skip a block.

runtime

Not a browser condition

@if cannot react to hover, scroll, or media at runtime. Use CSS for those.

else

Need an alternate branch?

Use @else or @else if — this page stays on single-branch optional styles.

css if()

Different from CSS if()

CSS is gaining its own if(). Sass @if is compile-time and never ships to the browser.

Sass Support

@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 @if.

Key Takeaways

  • Branch: @if <expr> { … } runs only when truthy.
  • Falsey: only false and null.
  • Combine: use and, or, and not in conditions.
  • Need a fallback? Continue with @else / @else if.

One line: @if is a compile-time switch — truthy runs the block; falsey skips it.

Compile Notes

@if never reaches the browser. Conceptual flow:

flow.txt
1. Evaluate the expression
2. Decide truthiness (only false and null fail)
3. Truthy → evaluate the block and emit CSS
4. Falsey → skip the block entirely
5. Continue compiling the rest of the stylesheet

Frequently Asked Questions

It controls whether its block is evaluated (including emitting CSS). If the expression is truthy, the block runs; if it is falsey, the block is skipped.
Only false and null. Every other value is truthy—including 0, empty strings, and empty lists.
Yes. Conditional expressions may use boolean operators: @if $a and $b { … }, @if $a or $b { … }, @if not $a { … }.
No. @if is compile-time only. Browsers see only the styles from blocks that evaluated to true.
@if decides whether one block runs. @else provides the alternate branch when the @if condition fails. See the dedicated Sass @else Rule page for two-way branches.
Inside mixins and functions for optional styles, feature flags, keyword checks, and any compile-time branch based on arguments or config variables.

Next: Sass @else Rule

Add a two-way fallback branch for themes, variants, and function returns.

Sass @else 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