Sass @while Rule

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

Definition and Usage

The Sass @while rule is written @while <expression> { … }. It evaluates its block while the expression is truthy, then checks again, until the expression finally becomes falsey.

Inside the block you almost always update variables the condition depends on — otherwise the loop never ends. Prefer @for for numeric ranges and @each for lists or maps when either will work.

Official pattern.

Per the Sass docs: scale-below() divides a value until it drops below a base — a classic @while use inside @function.

Compile-time only.

Browsers never see @while — only CSS or values the loop produces.

Prefer @for / @each.

Official docs: @while is needed for a few complex cases, but @for and @each are clearer and often faster to compile.

Syntax

SCSS
@use "sass:math";

/// Divides `$value` by `$ratio` until it's below `$base`.
@function scale-below($value, $base, $ratio: 1.618) {
  @while $value > $base {
    $value: math.div($value, $ratio);
  }
  @return $value;
}

$normal-font-size: 16px;

sup {
  font-size: scale-below(20px, 16px);
}

Pattern: check condition → run block → mutate state → repeat until falsey.

When to Use It

Pick the clearest loop for the job:

NeedPrefer
Count 1…n@for
Walk a list or map@each
Stop when a value crosses a threshold@while
Unknown iteration count / complex stop@while

SCSS Examples

Each example updates loop state so the condition can become falsey. Open View Compiled CSS for verified output.

Example 1 — scale-below()

Official pattern: divide by the golden ratio until the value drops below a base.

SCSS
@use "sass:math";

/// Divides `$value` by `$ratio` until it's below `$base`.
@function scale-below($value, $base, $ratio: 1.618) {
  @while $value > $base {
    $value: math.div($value, $ratio);
  }
  @return $value;
}

$normal-font-size: 16px;

sup {
  font-size: scale-below(20px, 16px);
}

How It Works

  1. Start at 20px with base 16px.
  2. While value > base, divide by 1.618.
  3. When it drops below, exit the loop.
  4. Return the shrunk size for font-size.

Example 2 — Manual Counter

Increment $i yourself — fine for learning; prefer @for for fixed ranges.

SCSS
$i: 1;

@while $i <= 4 {
  .step-#{$i} {
    order: $i;
  }
  $i: $i + 1;
}

How It Works

  1. Initialize $i before the loop.
  2. Emit a rule while $i <= 4.
  3. Always increment — without it, the loop never ends.
  4. For a fixed range, use @for $i from 1 through 4 instead.

Example 3 — Powers-of-Two List

Keep doubling until you pass a limit, then emit utilities with @each.

SCSS
@use "sass:list";

@function powers-of-two($start, $limit) {
  $n: $start;
  $out: ();

  @while $n <= $limit {
    $out: list.append($out, $n);
    $n: $n * 2;
  }

  @return $out;
}

$sizes: powers-of-two(4px, 32px);

@each $size in $sizes {
  .gap-#{$size} {
    gap: $size;
  }
}

How It Works

  1. @while builds the scale without a fixed step count.
  2. Double $n each pass until it exceeds $limit.
  3. @each turns the list into CSS classes.
  4. You do not need to know how many steps fit under the limit.

Example 4 — Halve Box Sizes

Emit size classes while the current size stays above a floor.

SCSS
@use "sass:math";

$size: 64px;
$base: 8px;
$i: 0;

@while $size > $base {
  .box-#{$i} {
    width: $size;
    height: $size;
  }
  $size: math.div($size, 2);
  $i: $i + 1;
}

How It Works

  1. Emit the current size, then halve it.
  2. Test is $size > $base — exclusive of the floor.
  3. After 16px, the next half is 8px, so the loop stops.
  4. Change > to >= if you want the floor included.

Example 5 — Strip Leading Zeros

Keep slicing while the first character is 0 (and length stays safe).

SCSS
@use "sass:string";
@use "sass:meta";

@function strip-leading-zeros($str) {
  @while string.index($str, "0") == 1 and string.length($str) > 1 {
    $str: string.slice($str, 2);
  }
  @return $str;
}

.result {
  --a: #{meta.inspect(strip-leading-zeros("00042"))};
  --b: #{meta.inspect(strip-leading-zeros("0"))};
  --c: #{meta.inspect(strip-leading-zeros("1050"))};
}

How It Works

  1. Index == 1 means the string starts with 0.
  2. Length guard keeps a lone "0" from vanishing.
  3. Slice from 2 drops the leading zero each pass.
  4. Inner zeros stay — only a leading run is removed.

Edge Cases & Pitfalls

Most @while bugs are missing updates, wrong stop tests, or using it when @for/@each would do.

infinite

Always mutate the condition

If you forget $i: $i + 1 (or the equivalent), the compiler can hang. Update every variable the test uses.

prefer

Known range? Use @for

Manual counters are harder to read. Reach for @for / @each first, per the official guidance.

truthy

0 is still truthy

Only false and null stop a condition. Do not rely on 0 alone as a stop signal.

bounds

> vs >= changes the last step

Threshold loops often miss or include the floor by one step. Check exclusive vs inclusive carefully.

Sass Support

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

Key Takeaways

  • Repeat: @while runs while the condition stays truthy.
  • Mutate state every pass so the loop can stop.
  • Prefer @for / @each when the range or items are known.
  • Great in functions that shrink or grow until a threshold.

One line: @while keeps going until the condition fails — update variables so it can.

Compile Notes

@while never reaches the browser. Conceptual flow:

flow.txt
1. Evaluate the condition
2. If falsey → exit the loop
3. If truthy → evaluate the block (emit CSS / update vars)
4. Go back to step 1
5. Continue compiling after the loop

Frequently Asked Questions

It evaluates a block while its condition expression is truthy, then checks again, until the condition finally becomes falsey.
Use @while for open-ended or complex stopping conditions. Prefer @for for numeric ranges and @each for lists or maps—they are clearer and often faster.
Only false and null are falsey. Empty strings, empty lists, and the number 0 are all truthy.
Yes, if the condition never becomes falsey. Always update the variables that the condition depends on, or the compiler may hang.
No. @while is compile-time only. Browsers see styles or values produced by the loop.
Yes. The official docs show scale-below(), which divides a value until it drops below a base—perfect inside @function.

Next: Sass Numbers

Units, math, and values you use in loop thresholds and scales.

Sass Numbers →

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