Operators & math.div
Sass can calculate while it compiles. You can double a spacing value, turn a column count into a percentage, or check whether one size is larger than another. The result is a plain number in your CSS, so the browser does no work at all.
In this lesson you will use the arithmetic, comparison and boolean operators, learn how units behave in maths, and learn why / no longer means division in Sass and what to use instead.
Arithmetic operators
Sass supports +, -, * and % (remainder) on numbers. Division is done with the function math.div() from the built-in sass:math module, which you load with @use "sass:math"; at the top of the file.
@use "sass:math";
$base: 16px;
$columns: 12;
.layout {
padding: $base * 1.5;
margin-top: $base + 4px;
gap: $base - 6;
width: math.div(600px, 960px) * 100%;
line-height: math.div(24px, $base);
}
.span-4 {
flex-basis: math.percentage(math.div(4, $columns));
}.layout {
padding: 24px;
margin-top: 20px;
gap: 10px;
width: 62.5%;
line-height: 1.5;
}
.span-4 {
flex-basis: 33.3333333333%;
}Look at how the units worked:
16px * 1.5keeps thepx.16px - 6treats the unitless6as pixels, giving10px.600px / 960pxcancels the units and leaves a plain number, which times100%gives a percentage.24px / 16pxgives a unitless1.5, perfect forline-height.math.percentage()turns a fraction into a percentage.
Units that do not mix
Sass can convert between absolute units it knows the size of, such as px, in, cm and pt. It cannot convert relative units such as em, rem, % or vw, because their real size depends on the page. Adding them is an error:
.box {
width: 100% - 2rem;
}100% and 2rem have incompatible units. ╷ 2 │ width: 100% - 2rem; │ ^^^^^^^^^^^ ╵ - 2:10 root stylesheet
The fix is calc(). Sass understands calc(): it simplifies the parts it can, inserts your variables, and leaves the rest for the browser.
$gutter: 16px;
$sidebar: 240px;
.main {
width: calc(100% - $sidebar - $gutter * 2);
min-height: calc(100dvh - 4rem);
}
.content {
padding: calc(1rem + 2vw);
}.main {
width: calc(100% - 240px - 32px);
min-height: calc(100dvh - 4rem);
}
.content {
padding: calc(1rem + 2vw);
}Sass replaced the variables and worked out $gutter * 2 as 32px, then left the rest of each calc() for the browser, which knows how wide 100% really is. Variables work directly inside calc() in current Dart Sass; very old code wrote calc(100% - #{$sidebar}) with interpolation, which still works but is no longer needed.
Why / is not division any more
In CSS, / is a separator, not division: font: 16px/1.5 serif, grid-area: 1 / 3, aspect-ratio: 16 / 9 and rgb(0 0 0 / 50%). Older Sass also used / for division, and had to guess which meaning you wanted. That guessing caused bugs, so Dart Sass 1.33 deprecated / for division. Today it still divides in some places but prints a warning:
$base: 16px;
.title {
width: $base / 2;
font: 16px/1.5 Georgia, serif;
}WARNING: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.
Recommendation: math.div($base, 2) or calc($base / 2)
More info and automated migrator: https://sass-lang.com/d/slash-div
line 4
.title {
width: 8px;
font: 16px/1.5 Georgia, serif;
}The plain 16px/1.5 in font was left alone as a separator, but $base / 2 divided and warned. The Sass team plans to release Dart Sass 2.0.0 around the end of 2026, and in it / outside calc() will always be a separator that builds a slash-separated list. Code like $base / 2 will then silently produce 16px/2 instead of 8px, so fix it now:
math.div($base, 2)for maths in Sass;calc($base / 2)when you want the browser-style expression (Sass simplifies it if it can).
Comparison and boolean operators
Sass compares values with ==, !=, <, <=, > and >=, and combines true/false values with and, or and not. You will use these mostly inside @if rules (Control Flow) and functions:
$base: 16px;
$columns: 12;
$dark-theme: false;
.debug {
a: $base == 16px;
b: 2rem > 1rem;
c: 1px * 3 != 3px;
d: ($columns > 10) and ($base < 20px);
e: not $dark-theme;
f: $dark-theme or ($columns == 12);
}.debug {
a: true;
b: true;
c: false;
d: true;
e: true;
f: true;
}The property names a to f are just labels so you can see the results in the output; real code would use these inside @if. Note that < and > only work on numbers with compatible units, and == compares the value and unit: 16px == 1rem is false.
String operators
+ also joins strings. If the first string is quoted, the result is quoted:
$city: "Pune";
.label::before {
content: $city + " Metro, Line 1";
font-family: "Noto Sans" + ", sans-serif";
}.label::before {
content: "Pune Metro, Line 1";
font-family: "Noto Sans, sans-serif";
}The first line is what you wanted. The second is a trap: the result is one quoted string, "Noto Sans, sans-serif", which the browser reads as a single font name that does not exist. A font list is a comma-separated list, so write it directly: font-family: "Noto Sans", sans-serif;. For anything more than joining, use Interpolation or the sass:string module.
Common mistakes
$a / $bfor division. It warns now and will mean something else in Dart Sass 2. Usemath.div($a, $b).- Mixing
%orremwithpxoutsidecalc(). Sass cannot know the size; usecalc()and let the browser do it. - Forgetting
@use "sass:math";. Without it,math.divis an unknown function and the call is left as plain text. - Comparing values with different units.
10px > 2emis an error, because Sass cannot convertem.
Key points
+,-,*and%work on numbers; units multiply, cancel and convert when Sass knows their size.- Divide with
math.div()fromsass:math;/for division is deprecated and becomes a separator in Dart Sass 2. - Relative units (
%,em,rem,vw) cannot mix withpxat compile time; usecalc(), which accepts Sass variables directly. ==,!=,<,>and friends compare values;and,orandnotcombine booleans.+joins strings; a quoted first string gives a quoted result.
Exercise
A Jaipur textile shop's product grid is 1140px wide with 4 columns and a 24px gap. Using sass:math, calculate each column's width in pixels ((1140px - 3 * 24px) / 4) and as a percentage of the grid. Set .col with width as the percentage and max-width as the pixel value, and .grid with gap and a width of calc(100% - 2rem). Do not use / for division.
Show solution
@use "sass:math";
$grid: 1140px;
$columns: 4;
$gap: 24px;
$col-px: math.div($grid - ($columns - 1) * $gap, $columns);
.grid {
gap: $gap;
width: calc(100% - 2rem);
}
.col {
width: math.percentage(math.div($col-px, $grid));
max-width: $col-px;
}$col-px works out to 267px, and dividing it by 1140px cancels the units, so math.percentage() gives about 23.42%.
Quick Quiz
1. Which is the modern way to divide $width by 2?
Slash division is deprecated; math.div() from sass:math is the replacement.
2. What happens to 100% - 2rem outside calc()?
Sass cannot convert percentages to rem; wrap the expression in calc().
3. In Dart Sass 2, what will 16px / 2 outside calc() produce?
Dart Sass 2 will treat / as a separator, matching CSS.
4. What does math.div(24px, 16px) return?
Dividing two pixel values cancels the units.
Learn Sass with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
