Chepter 4: Sass Variables
Sass Variables — the single most loved feature that makes almost everyone switch from plain CSS to Sass.
I’m going to explain this like we’re building a real mini-project together — very detailed, step-by-step, with lots of live examples, gotchas, modern 2026 best practices, and why variables still beat native CSS custom properties in many real-world cases.
1. What Are Sass Variables? (Super Simple First)
A Sass variable is just a named box where you store a value once, and then reuse that name everywhere instead of repeating the value.
- You write: $primary: #6c5ce7;
- Then everywhere you want that purple color → just write $primary
Magic moment: Change the value in one place → entire project updates automatically after recompile.
This solves the classic pain: “Wait… our brand blue is used 147 times… now marketing wants a new shade… kill me.”
2. Basic Declaration Syntax (SCSS – the one we use)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Anywhere in your .scss file (usually at the top or in _variables.scss) $primary: #6c5ce7; // color $font-stack: "Inter", system-ui, -apple-system, sans-serif; $spacing: 1.6rem; // number + unit $border-rad: 12px; $shadow-sm: 0 4px 12px rgba(black, 0.08); $enabled: true; // boolean $themes: ("light", "dark"); // list $breakpoints: ( sm: 576px, md: 768px, lg: 992px, xl: 1200px ); // map – very powerful! |
- Name must start with $
- Value can be almost anything Sass understands (colors, numbers, strings, lists, maps, functions…)
- No !important or CSS-specific junk — just pure values
3. Using Variables (Everyday Examples)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
body { font-family: $font-stack; color: $primary; margin: 0; } .btn { background: $primary; color: white; padding: $spacing * 0.75 $spacing * 1.5; // math works! border-radius: $border-rad; box-shadow: $shadow-sm; transition: background 0.2s; &:hover { background: darken($primary, 12%); // Sass color functions — love this } } @media (min-width: map-get($breakpoints, md)) { // map access .container { max-width: map-get($breakpoints, lg); } } |
See? Clean, readable, maintainable.
4. Scope – Global vs Local (Very Important in 2026)
- Global: Declared outside any {} block → available everywhere in that module/file (and to files that @use it)
- Local: Declared inside a block (rule, mixin, function) → only lives inside that block
Example:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Global $theme-color: #e84393; .card { // Local – shadows the global one inside this block only $theme-color: #00b894; background: $theme-color; // → green (#00b894) border: 1px solid darken($theme-color, 15%); } .footer { background: $theme-color; // → still pink (#e84393) – global unchanged } |
Pro tip: Avoid shadowing unless you really mean it — can confuse you later.
5. !default Flag – The Library Hero (Modern Sass loves this)
Used in libraries/frameworks so users can override defaults without editing core files.
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// _buttons.scss (library file) $btn-padding-y: 0.75rem !default; $btn-padding-x: 1.5rem !default; $btn-radius: 0.375rem !default; .btn { padding: $btn-padding-y $btn-padding-x; border-radius: $btn-radius; } |
Now in your main file:
|
0 1 2 3 4 5 6 7 8 9 10 11 |
// style.scss @use 'buttons' with ( $btn-padding-y: 1rem, $btn-padding-x: 2rem, $btn-radius: 999px // pill buttons! ); |
→ You customized the library without touching its code. Beautiful!
6. Variable Interpolation (Where You Can & Cannot Use Variables)
You can put variables almost anywhere:
- In values: color: $primary;
- In calculations: padding: $spacing * 2;
- In selectors (with #{}):
SCSS0123456789101112$component: "card";.#{$component} {// becomes .card}.#{$component}__title { ... }
But you cannot interpolate inside the variable name itself:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// ❌ This does NOT work $color-warning: #ffc107; .alert-#{$type} { ... } // Invalid // ✓ Correct way → use maps $alerts: ( success: #28a745, warning: #ffc107, danger: #dc3545 ); .alert { &--warning { background: map-get($alerts, warning); } } |
7. Sass vs CSS Variables (Custom Properties) – 2026 Honest Comparison
| Feature | Sass Variables $ | CSS Variables –var | Winner for large projects? |
|---|---|---|---|
| Value set once, compile-time | Yes | No – runtime | Sass |
| Can use in selectors/math fully | Yes | Limited (calc() only in some places) | Sass |
| Color functions (darken etc.) | Built-in rich set | color-mix(), relative color syntax | Sass (easier still) |
| Live change per element | No | Yes (great for themes) | CSS |
| No build step needed | No (needs compiler) | Yes | CSS |
| Scoped to component easily | With modules (@use) | With :root or shadow DOM | Tie |
Verdict in 2026: Use Sass variables for design tokens, colors, spacing scales, typography in big projects/libraries. Use CSS custom properties for dynamic runtime theming (dark mode per-user, etc.). Many teams use both together!
8. Modern Best Practices (2026 Edition)
- Put all variables in _variables.scss or _tokens.scss
- Use @use ‘variables’; in other files (never old @import)
- Prefer maps over tons of separate variables
- Use kebab-case or snake_case — Sass treats $font-size and $font_size the same
- Add units to numbers when needed ($spacing: 16px !default;)
- Use !default everywhere in shared/library code
- Avoid re-assigning globals without !global (and even then — sparingly)
Quick Challenge for You
Try this in your editor:
- Create _colors.scss
|
0 1 2 3 4 5 6 7 |
$primary: #6c5ce7 !default; $success: #00b894 !default; |
- In style.scss
|
0 1 2 3 4 5 6 7 8 9 10 |
@use 'colors' with ( $primary: #9b59b6 // override to new purple ); body { background: colors.$primary; } |
Compile → see the override in action!
You’ve now mastered Sass variables — the foundation of everything else (mixins, maps, themes…).
Next class — want to go into Sass Maps + Lists (super useful for themes/buttons)? Or color functions with real examples? Or how to structure variables in a medium-sized project?
Just say the word — I’m here! 🚀
