Operators
|
This section documents Sass/SCSS as implemented by Dart Sass, the current official and actively maintained compiler — it is not tied to any specific book, build tool, or CSS framework (Bootstrap, Bulma, etc.). Unlike the other reference sections on this site, no single reference book underpins it: the content was generated with the assistance of AI from general knowledge of Dart Sass, and should be verified against the current official documentation at sass-lang.com before relying on it in production. Sass continues to evolve, so behaviour described here may lag the compiler you are actually running. This section’s bibliography lists the reference material consulted while preparing these pages. |
Sass evaluates expressions at compile time, so arithmetic, comparisons, and boolean logic can be written directly in property values, variable declarations, and control-flow conditions. Everything on this page is resolved before the browser ever sees the stylesheet.
Arithmetic
| Operator | Meaning | Example |
|---|---|---|
|
Addition (also string concatenation) |
|
|
Subtraction |
|
|
Multiplication |
|
|
Modulo (remainder) |
|
|
Division |
|
@use "sass:math";
$base: 8px;
$gutter: $base * 2; // 16px
$half: math.div($gutter, 2); // 8px
$rest: $base % 3; // 2px
.grid {
gap: $gutter;
padding: $base + 4px; // 12px
width: math.div(100%, 3); // 33.3333333333%
}
Division: use math.div(), not /
This is the single most important gotcha in Sass arithmetic. / was historically overloaded: it means division
in Sass, but it is also plain CSS syntax in values such as font: 16px/1.5 and grid-area: 1 / 3. Sass had to
guess which was meant, and the heuristics were a frequent source of bugs.
Dart Sass therefore deprecated / as a division operator. Use math.div():
@use "sass:math";
// Deprecated -- emits a warning, and may not divide at all
$bad: 100px / 3;
// Correct
$good: math.div(100px, 3); // 33.3333333333px
/ is now treated as a plain separator, so font: 16px/1.5 and grid-area: 1 / 3 pass through to the CSS
untouched, which is what you want. To build a slash-separated value from variables, use list.slash() or
interpolation:
@use "sass:list";
$size: 16px;
$lh: 1.5;
.a { font: #{$size}/#{$lh} sans-serif; } // via interpolation
.b { font: list.slash($size, $lh) sans-serif; }
Note that interpolation produces an unquoted string, so the result can no longer be used in further arithmetic.
Units
Sass tracks units and applies real dimensional analysis, which catches genuine mistakes at compile time:
@use "sass:math";
$a: 10px + 5px; // 15px -- same unit, fine
$b: 10px * 2; // 20px -- unit × unitless
$c: math.div(10px, 2); // 5px -- unit ÷ unitless
$d: math.div(10px, 2px); // 5 -- units cancel, result is unitless
$e: 10px * 2px; // 20px*px -- valid but almost never useful
$f: 10px + 5; // ERROR: 10px and 5 have incompatible units
$g: 1in + 10px; // 1.1041666667in -- compatible units are converted
Two consequences worth internalising:
-
Multiplying two lengths gives you
px*px, which is not a valid CSS unit. If you find yourself writing$a * $bwith both carrying units, one of them should probably be unitless. -
To strip a unit, divide by one of the same unit —
math.div($n, ($n * 0 + 1))— or usemath.div($n, 1px)when you know the unit.
% is a unit like any other in Sass, so 50% + 10% works but 50% + 10px is an error.
Arithmetic and calc()
CSS’s calc() is evaluated by the browser, not by Sass. Modern Dart Sass parses calc() expressions and will
simplify them where it can, but a variable used inside one must be interpolated:
$sidebar: 280px;
.main {
width: calc(100% - #{$sidebar}); // → calc(100% - 280px)
}
Use calc() when the computation genuinely needs runtime values — mixing % with px, or referencing a CSS
custom property. Use Sass arithmetic when everything is known at build time, since it produces a plain literal
and costs the browser nothing.
String operators
+ concatenates strings. The quoting of the left operand determines the quoting of the result:
$a: "foo" + "bar"; // "foobar" (quoted)
$b: "foo" + bar; // "foobar" (quoted -- left operand wins)
$c: foo + "bar"; // foobar (unquoted)
$d: foo + bar; // foobar (unquoted)
- and / between unquoted strings produce hyphen- and slash-separated unquoted strings, which is occasionally
useful but usually clearer via interpolation.
In practice, interpolation is the better tool for building strings, especially where a value must become part of a selector or property name:
$icon: "chevron";
$dir: left;
.icon-#{$icon}-#{$dir} {
background-image: url("/icons/#{$icon}-#{$dir}.svg");
margin-#{$dir}: 4px;
}
See Built-in Modules for sass:string functions such as string.quote()
and string.unquote().
Comparison operators
| Operator | Meaning | Example |
|---|---|---|
|
Equal |
|
|
Not equal |
|
|
Less than |
|
|
Greater than |
|
|
Less than or equal |
|
|
Greater than or equal |
|
== and != work on every Sass type. The relational operators (<, >, ⇐, >=) apply only to numbers,
and the numbers must have compatible units:
@if 768px < 1024px { /* true */ }
@if 1in > 50px { /* true -- units converted */ }
@if 10px > 5 { /* ERROR: incompatible units */ }
Equality is strict about type: 1 == 1px is false, and "foo" == foo is true (quoting does not affect
string equality). It is also case-sensitive throughout — 1px == 1PX is false (unit names are compared
character-for-character, unlike in plain CSS) and "a" == "A" is false for strings.
Boolean operators
Sass uses the words and, or, and not — not &&, ||, or !.
@use "sass:math";
@mixin responsive-font($size, $scale: true) {
@if $scale and $size > 16px {
font-size: math.div($size, 1.2);
} @else if not $scale or $size <= 16px {
font-size: $size;
}
}
and and or short-circuit, so the right operand is not evaluated when the left already decides the result.
Truthiness: everything is truthy except false and null. Notably 0, "" (the empty string), and ()
(the empty list) are all truthy in Sass — the opposite of JavaScript. This trips people up regularly:
$value: 0;
@if $value { /* this RUNS -- 0 is truthy in Sass */ }
$missing: map.get($config, nope); // returns null when absent
@if $missing { /* correctly skipped -- null is falsy */ }
Precedence
From highest to lowest:
-
Unary
not, unary- -
*,%, andmath.div()calls -
+,- -
<,⇐,>,>= -
==,!= -
and -
or
Parentheses override precedence and are worth adding freely — they cost nothing in the output and make intent obvious:
@use "sass:math";
$a: 2 + 3 * 4; // 14
$b: (2 + 3) * 4; // 20
$c: math.div($total, $count) + 1; // clearer than relying on precedence
One caveat: parentheses around a comma-separated value create a list, not a grouped expression — (1, 2)
is a two-element list, while (1 + 2) is the number 3. See Lists & Maps.