Skip to content

Sass: @while

How Sass @while directive works, including its syntax, use cases for conditional loops, and performance considerations compared to @each and @for.

@while

The @while rule, written @while <expression> { ... }, evaluates its block if its expression returns true. Then, if its expression still returns true, it evaluates its block again. This continues until the expression finally returns false.

The .scss file:

@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);
}

and the .css file:

sup {
  font-size: 12.36094px;
}

How it works step by step

The function scale-below(20px, 16px) divides 20px by 1.618 repeatedly until the result is below 16px:

Iteration Value $value > 16px?
Start 20px yes
1 12.36094px no, stop

math.div(20px, 1.618) equals approximately 12.36px, which is below the 16px base, so the loop stops after one iteration and returns the value.

Generating rules with @while

@while can also generate CSS rules. A common pattern is building a z-index scale, where each level gets a fixed increment:

$z-index: 1;

@while $z-index <= 5 {
  .layer-#{$z-index} {
    z-index: $z-index * 10;
  }
  $z-index: $z-index + 1;
}
.layer-1 {
  z-index: 10;
}
.layer-2 {
  z-index: 20;
}
.layer-3 {
  z-index: 30;
}
.layer-4 {
  z-index: 40;
}
.layer-5 {
  z-index: 50;
}

@while vs @for vs @each

Directive Best when Iteration control
@for You know the start and end values Fixed numeric range
@each You want to iterate over a list or map Each item in a collection
@while The stop condition is dynamic / computed Custom, you manage the counter

Avoiding infinite loops

Because @while doesn't manage its own counter, it's easy to accidentally write a loop that never ends. Two safeguards help:

  1. Always modify the loop variable inside the block so the condition will eventually be false.
  2. Add a safety cap, i.e., a counter that breaks the loop after a maximum number of iterations:
@function scale-below($value, $base, $ratio: 1.618) {
  $iterations: 0;
  @while $value > $base and $iterations < 100 {
    $value: math.div($value, $ratio);
    $iterations: $iterations + 1;
  }
  @return $value;
}

Summary

  • @while <expression> repeats its block as long as the expression is truthy.
  • The expression is re-evaluated before each iteration; the loop stops when it returns false.
  • You must update the loop variable yourself. Sass does not auto-increment.
  • Prefer @for for known ranges and @each for lists/maps; reach for @while only when the stop condition is dynamic.
  • Add a safety cap to guard against accidental infinite loops.
Navigation