Sass variables store values under $names. This page covers declarations, Sass vs CSS variables, scope, !default, !global, maps instead of dynamic names, and five compiled examples.
01
Declare
$name:
02
vs CSS
Compile-time
03
Scope
Global / local
04
!default
Configure libs
05
!global
Update outer
06
Practice
5 examples
Concept
What Are Sass Variables?
Official docs: assign a value to a name that begins with $, then refer to that name instead of repeating the value. Variables reduce repetition, enable math and theming, and help configure libraries.
A declaration looks like a property ($name: value;) but can appear almost anywhere—not only inside style rules.
Compiled away—the CSS file contains the final values, not $names.
Imperative: using a variable snapshots its current value.
Hyphens and underscores are equivalent ($font-size = $font_size).
Cannot invent variable names with interpolation—use a map instead.
💡
Beginner tip
Start with a small set of brand tokens ($brand, $space, $radius) at the top of a file or module, then build everything else from them.
Official docs: CSS has its own variables (--token), and they are totally different from Sass $variables.
Sass $var
CSS --var
Compiled away
Kept in the CSS output
One value at a time
Can differ per element
Imperative (earlier uses keep old value)
Declarative (later changes can affect uses)
Libraries
⚡ Default Values (!default)
Official docs: normally a new assignment overwrites the old value. With !default, Sass assigns only if the variable is undefined or null. Libraries use this so consumers can configure tokens first.
With @use, you can also configure module defaults: @use "library" with ($black: #222);
Scope
🏢 Scope, Shadowing & !global
Top-level variables are global within their module.
Inside blocks (rules, mixins, …) variables are usually local.
Shadowing — a local $name can hide a global one without changing it.
!global — assign to the existing top-level variable from inside a block.
💡
Heads up
Modern Dart Sass only allows !global on variables already declared at the top level—it cannot create a brand-new global from inside a block.
Flow control scope: variables inside @if / loops do not shadow outer variables at the same level—they assign to them. Declare the variable first (even as null) before conditionally updating it.
Advanced
🧮 Built-ins & Dynamic Names
Variables from built-in modules (like math.$pi) cannot be reassigned. For “dynamic variable names,” store values in a map and look them up with map.get—Sass does not allow $theme-#{$name} style declarations.
Helpers such as meta.variable-exists() and meta.global-variable-exists() can inspect the current or global scope when needed.
Cheat Sheet
⚡ Quick Reference
Goal
Code
Declare
$brand: #036;
Use
color: $brand;
Default if unset
$brand: #036 !default;
Set global from block
$brand: #000 !global;
Configure a module
@use "lib" with ($brand: #222);
Dynamic keys
map.get($theme, "warning")
Hands-On
Examples Gallery
Each example shows a core variable behavior. Open View Compiled CSS for verified output.
📚 Getting Started
Declare, reuse, and see how reassignment works over time.
Example 1 — Declare and Reuse
Official-docs style: derive a border color from a base brand color.
Change $base-color once and every derived token that uses it updates at compile time. No $ names remain in the CSS.
Example 2 — Imperative Values (Earlier Uses Stick)
Reassigning later does not rewrite earlier rules that already used the variable.
styles.scss
$variable: value 1;
.rule-1 {
value: $variable;
}
$variable: value 2;
.rule-2 {
value: $variable;
}
📤 Compiled CSS:
.rule-1 {
value: value 1;
}
.rule-2 {
value: value 2;
}
How It Works
Each use captures the value at that moment. This is the opposite of CSS custom properties, which are declarative.
📈 Scope, Globals & Configuration
Local shadowing, !global updates, !default, and map tokens.
Example 3 — Global vs Local Scope
Top-level variables are visible later; block variables stay inside their block.
styles.scss
$global-variable: global value;
.content {
$local-variable: local value;
global: $global-variable;
local: $local-variable;
}
.sidebar {
global: $global-variable;
// $local-variable is not available here
}
📤 Compiled CSS:
.content {
global: global value;
local: local value;
}
.sidebar {
global: global value;
}
How It Works
$local-variable never leaks into .sidebar. That prevents accidental cross-rule coupling.
Example 4 — Update a Global with !global
Assign inside a rule, but write to the existing top-level variable.
styles.scss
$variable: first global value;
.content {
$variable: second global value !global;
value: $variable;
}
.sidebar {
value: $variable;
}
📤 Compiled CSS:
.content {
value: second global value;
}
.sidebar {
value: second global value;
}
How It Works
Without !global, the inner assignment would only shadow. With it, both rules see the updated global value.
Example 5 — !default, Flow Control & Maps
Configure theme colors, adjust them in @if, and look up tokens from a map.
!default keeps earlier user settings. The @if block updates the outer theme variables. The map avoids illegal dynamic $theme-#{} names. Hyphen/underscore aliases share one variable.
Theming — toggle flags then adjust related variables.
DRY math — compute derived sizes from one base unit.
Named palettes — maps when keys must be dynamic.
🧠 How Compilation Works
1
Declare / configure
Set $names, optionally with !default or @use with.
Define
2
Resolve each use
Substitute the current value in scope (imperative snapshot).
Use
3
Maybe reassign
Later assignments affect only later uses unless !global.
Update
4
✓
CSS ships
Only concrete values remain—no $variables in the file.
Watch Out
⚠️ Common Pitfalls
Confusing with CSS --vars — Sass variables do not cascade in the browser.
Expecting earlier rules to update — reassignment is imperative.
Accidental locals — assigning inside a block without !global shadows.
Dynamic $name-#{} — not allowed; use a map.
Using !global to create new globals — declare at top level first.
Pro Tips
💡 Best Practices
✅ Do
Keep shared tokens at the module top level
Use !default for library-configurable settings
Prefer maps for families of related named values
Name variables by meaning ($brand, not $blue2)
Combine Sass tokens with CSS variables when runtime theming is needed
❌ Don’t
Scatter magic numbers that should be tokens
Assume CSS var(--x) rules apply to $x
Build variable names with interpolation
Overwrite globals from deep nests without !global on purpose
Forget that hyphens and underscores share one name
Summary
Key Takeaways
Knowledge Unlocked
Five things to remember about Sass variables
$names, compile-time values, scope, and safe configuration.
5
Core concepts
📝01
$name
store a value
Basics
⚙️02
Compile-time
not in CSS
Stage
🏢03
Scope
global / local
Rules
⚡04
!default
configure libs
API
✓05
Maps
dynamic keys
Pattern
❓ Frequently Asked Questions
Names that start with $ and hold a value. You declare $name: value; then use $name anywhere that value is allowed.
Sass variables are compiled away and have one value at a time (imperative). CSS custom properties stay in the CSS and can differ per element (declarative).
It assigns a value only if the variable is undefined or null. Libraries use it so users can configure values before the library runs.
It assigns to the global variable from inside a local block. The global variable must already exist at the top level.
No. Sass treats hyphens and underscores as the same in identifiers, so both names refer to one variable.
No. Use a map and map.get() when you need dynamic names, instead of $theme-#{$name}.
Did you know?
Official Sass docs note that hyphens and underscores are treated as identical in variable names—a historical compatibility detail from when Sass only allowed underscores.
Sass variables are compile-time $names for reusable values. Master scope, !default for libraries, and maps for dynamic keys—and remember they are not the same as CSS custom properties.