Built-in Modules: math, string & meta
Sass ships with a standard library of ready-made functions, grouped into built-in modules. You have already met sass:map, sass:list and math.div(). This lesson tours the rest of sass:math, the text tools in sass:string, and sass:meta, which lets your code inspect values and other code. Colours have their own lesson next: Colour Functions & Colour Spaces.
You load a built-in module like any other module, with @use "sass:name", and call its members through the namespace. Built-in modules are always available, so every example in this lesson runs in the editor.
The seven built-in modules
| Module | Typical use | Examples |
|---|---|---|
sass:math | Numbers and units | math.div(), math.round(), math.clamp(), math.$pi |
sass:string | Text | string.slice(), string.index(), string.to-upper-case() |
sass:color | Colours | color.scale(), color.mix(), color.to-space() |
sass:list | Lists | list.nth(), list.append(), list.join() |
sass:map | Maps | map.get(), map.merge(), map.deep-merge() |
sass:selector | Selectors | selector.nest(), selector.append() |
sass:meta | Types and code | meta.type-of(), meta.call(), meta.load-css() |
sass:math
Besides math.div(), the maths module rounds numbers, picks the largest or smallest, and checks units:
@use "sass:math";
@debug math.round(4.6px);
@debug math.ceil(4.2);
@debug math.floor(4.8);
@debug math.max(3px, 9px, 5px);
@debug math.clamp(10px, 4px, 20px);
@debug math.pow(2, 10);
@debug math.sqrt(16);
@debug math.unit(16px);
@debug math.is-unitless(1.5);
@debug math.compatible(1in, 1px);
$circle: 120px;
.ring {
width: $circle;
stroke-dasharray: math.round(math.$pi * $circle);
}line 3 DEBUG: 5px
line 4 DEBUG: 5
line 5 DEBUG: 4
line 6 DEBUG: 9px
line 7 DEBUG: 10px
line 8 DEBUG: 1024
line 9 DEBUG: 4
line 10 DEBUG: px
line 11 DEBUG: true
line 12 DEBUG: true
.ring {
width: 120px;
stroke-dasharray: 377px;
}Notes on the less obvious ones:
math.clamp($min, $value, $max)keeps a value inside a range while compiling:4pxwas raised to the minimum10px. It is different from CSSclamp(), which the browser works out live.math.unit()returns a number's unit as a string, andmath.is-unitless()checks for none. Both are useful for checking arguments in your own functions.math.compatible()tells you whether two numbers can be added:inandpxcan,pxandremcannot.math.$piis a module variable, written with the namespace before the$.
There is also math.random(), which gives a different number on every compile. Avoid it in real stylesheets, because each build changes your CSS for no reason.
sass:string
String functions let you take apart and build names. Positions start at 1, like lists:
@use "sass:string";
$class: "ec-btn-primary";
@debug string.length($class);
@debug string.index($class, "btn");
@debug string.slice($class, 4, 6);
@debug string.insert("btn", "ec-", 1);
@debug string.to-upper-case("pune");
@debug string.split($class, "-");
@debug string.unquote(".card");
@debug string.quote(bold);
.badge::after {
content: string.to-upper-case("new");
}line 5 DEBUG: 14
line 6 DEBUG: 4
line 7 DEBUG: btn
line 8 DEBUG: ec-btn
line 9 DEBUG: PUNE
line 10 DEBUG: ["ec", "btn", "primary"]
line 11 DEBUG: .card
line 12 DEBUG: bold
.badge::after {
content: "NEW";
}string.index()finds where a piece starts (or returnsnull).string.slice($string, $start, $end)cuts out a piece; both ends are included.string.split()(Dart Sass 1.57 and later) breaks a string into a bracketed list.string.quote()andstring.unquote()add or remove quotes. CSS needs quotes in some places (content, font names with spaces) and not in others (selectors, keywords).
sass:meta
sass:meta lets your code ask questions about values and other code. The most useful members for everyday work:
@use "sass:math";
@use "sass:meta";
@function rem($px) {
@if meta.type-of($px) != number or math.unit($px) != "px" {
@return $px;
}
@return math.div($px, 16px) * 1rem;
}
@debug meta.type-of(12px);
@debug meta.type-of("Lucknow");
@debug meta.type-of(#cc6699);
@debug meta.type-of((a: 1));
@debug meta.inspect((brand: #cc6699, space: (sm: 4px)));
@debug meta.function-exists("rem");
.title {
font-size: rem(24px);
margin: rem(auto);
padding: meta.call(meta.get-function("rem"), 8px);
}line 11 DEBUG: number
line 12 DEBUG: string
line 13 DEBUG: color
line 14 DEBUG: map
line 15 DEBUG: (brand: #cc6699, space: (sm: 4px))
line 16 DEBUG: true
.title {
font-size: 1.5rem;
margin: auto;
padding: 0.5rem;
}meta.type-of()returnsnumber,string,color,list,map,bool,nulland a few others. Therem()function uses it to pass values likeautothrough untouched instead of failing.meta.inspect()turns any value into a readable string, which is handy inside@debugand error messages.meta.function-exists(),meta.variable-exists()andmeta.mixin-exists()check whether a name is defined at this point.meta.get-function()turns a function into a value you can store or pass around, andmeta.call()calls it. Libraries use this to let users pass in their own functions.
One member of sass:meta needs real files, so it is shown as plain code: meta.load-css() is a mixin that loads another module's CSS inside a rule, which is handy for scoping a whole theme under a class:
@use "sass:meta";
.theme-dark {
@include meta.load-css("themes/dark");
}Every rule from themes/_dark.scss is written with .theme-dark in front of it. Unlike @use, it can appear anywhere, and it accepts a $with map to configure the module.
Common mistakes
- Forgetting the
@useline. Without@use "sass:string";,string.slice()is an error (the message isThere is no module with namespace "string".). - Counting from 0 in strings. The first character is position 1.
- Confusing
math.clamp()with CSSclamp(). The first is fixed at compile time; the second responds to the screen. - Comparing units with
==on strings.math.unit()returns a quoted string, so compare with"px", notpx.
Key points
- Built-in modules are loaded with
@use "sass:math"and so on, and their members use the namespace:math.round(),math.$pi. sass:mathrounds, clamps and checks units;math.compatible()tells you if two units can be combined.sass:stringmeasures, searches, slices, splits and changes the case of strings, counting from 1.sass:metachecks types (meta.type-of()), prints values (meta.inspect()), and calls functions dynamically (meta.call()).meta.load-css()includes another module's CSS inside a rule, which is useful for scoped themes.
Exercise
Write a function px-to-rem($value) for a Kochi news site that converts only pixel numbers to rem (16px base) and returns everything else unchanged. Use meta.type-of() and math.unit(). Test it with @debug on 24px, 1.5em, 0 and auto. Then use it on .headline for a 28px font size and for both parts of margin: 0 auto (call it once for each value).
Show solution
@use "sass:math";
@use "sass:meta";
@function px-to-rem($value) {
@if meta.type-of($value) == number and math.unit($value) == "px" {
@return math.div($value, 16px) * 1rem;
}
@return $value;
}
@debug px-to-rem(24px);
@debug px-to-rem(1.5em);
@debug px-to-rem(0);
@debug px-to-rem(auto);
.headline {
font-size: px-to-rem(28px);
margin: px-to-rem(0) px-to-rem(auto);
}Only 24px and 28px are converted (to 1.5rem and 1.75rem). 1.5em, the unitless 0 and the keyword auto fail the check and come back unchanged.
Quick Quiz
1. How do you read the value of pi from the math module?
Module variables are written as namespace, dot, then the variable with its $.
2. What does string.slice("ec-btn-primary", 4, 6) return?
Positions start at 1 and both ends are included, so characters 4 to 6 are btn.
3. What does meta.type-of(#cc6699) return?
Colours are their own Sass type.
4. Which is true about math.clamp(10px, 4px, 20px)?
math.clamp() is evaluated by Sass; CSS clamp() is evaluated by the browser.
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
