Variables

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.

A Sass variable stores a value under a name so it can be written once and reused everywhere. Variables are resolved entirely at compile time: by the time the browser sees the stylesheet, every reference has been replaced by the literal value it held.

Declaring and using variables

A declaration is a name prefixed with $, a colon, and a value:

$primary: #3f51b5;
$font-stack: "Inter", "Helvetica Neue", sans-serif;
$gutter: 16px;
$max-content-width: 72ch;

body {
  font-family: $font-stack;
  color: $primary;
  max-width: $max-content-width;
  padding: $gutter;
}

Compiles to:

body {
  font-family: "Inter", "Helvetica Neue", sans-serif;
  color: #3f51b5;
  max-width: 72ch;
  padding: 16px;
}

Any Sass value may be stored: numbers (with or without units), strings, colors, booleans, null, lists, and maps (see Lists & Maps). Hyphens and underscores are interchangeable in variable names, so $line-height and $line_height refer to the same variable.

Variables can be used anywhere a value is expected, including inside other variable declarations and in interpolation for places that aren’t value positions:

$base: 8px;
$gutter: $base * 2;      // arithmetic -- see the Operators page
$breakpoint-md: 768px;

@media (min-width: $breakpoint-md) {
  .grid { gap: $gutter; }
}

$side: left;
.callout {
  border-#{$side}: 3px solid $primary;   // interpolation: builds the property name
}

Interpolation (#{…​}) is required whenever the variable’s value must become part of a selector, a property name, or a string rather than a whole value on its own.

Scope

A variable declared at the top level of a stylesheet is global — visible to the rest of that file and, via @use, to files that load it. A variable declared inside a block (a style rule, mixin, function, or control directive) is local: it exists only until that block ends.

$colour: red;         // global

.alpha {
  $colour: blue;      // local -- shadows the global inside .alpha only
  color: $colour;     // blue
}

.beta {
  color: $colour;     // red -- the global was never modified
}

Assigning to an existing name inside a block creates a new local variable that shadows the global; it does not reassign it. To deliberately reach out and change the global from inside a block, add the !global flag:

$theme: light;

@mixin activate-dark-theme {
  $theme: dark !global;   // reassigns the global variable
}

.page {
  @include activate-dark-theme;
}

.footer::after {
  content: "#{$theme}";   // "dark"
}

!global may only be used on a variable that already exists at the global level; using it to create a new global is an error in Dart Sass. In practice !global is best avoided — action-at-a-distance mutation makes stylesheets hard to reason about, and configuring a module with @use …​ with (see Partials & Modules) or passing arguments to a mixin is almost always the clearer alternative.

Control-flow blocks are a deliberate exception to the shadowing rule: @if, @each, @for, and @while bodies can assign to variables in the enclosing scope directly, which is what makes accumulator patterns work.

$total: 0;
@each $w in 10px, 20px, 30px {
  $total: $total + $w;   // updates the outer $total, no !global needed
}
// $total is now 60px

Default values with !default

The !default flag assigns a value only if the variable is currently undefined or null. This is the mechanism that makes a Sass library configurable: the library declares its knobs with !default, and a consumer overrides whichever ones it cares about.

// _theme.scss  (the library)
$primary:      #3f51b5 !default;
$radius:       4px      !default;
$font-stack:   sans-serif !default;

.button {
  background: $primary;
  border-radius: $radius;
  font-family: $font-stack;
}

A consumer configures it at load time:

// main.scss
@use "theme" with (
  $primary: #e91e63,
  $radius: 12px
);
// $font-stack keeps its !default value of sans-serif

Without !default, the library’s assignment would unconditionally clobber whatever the consumer supplied. The rule of thumb is simple: every variable in a file intended to be loaded by others should carry !default.

Sass variables vs. CSS custom properties

The two look similar and solve overlapping problems, but they run at completely different times, and the distinction matters:

Sass variable ($name) CSS custom property (--name)

Resolved

At compile time

At runtime, by the browser

Present in output CSS

No — substituted away

Yes — shipped and live in the cascade

Changeable at runtime

No

Yes (via JavaScript, media queries, a class on an ancestor)

Cascades / inherits

No — lexical scope only

Yes — follows the DOM

Usable in Sass arithmetic

Yes

Not directly (the value is opaque to the compiler)

Use a Sass variable for values fixed at build time — a spacing scale, a breakpoint used in a @media query, anything you want to do arithmetic on. Use a CSS custom property for values that must change in the browser, such as a runtime-switchable theme. They combine well: a Sass variable can define a custom property.

$primary: #3f51b5;

:root {
  --primary: #{$primary};       // interpolation is required here
}

[data-theme="dark"] {
  --primary: #7986cb;           // switched at runtime, no recompile
}

.button { background: var(--primary); }

Note the interpolation: writing --primary: $primary; would emit the literal text $primary, because custom property values are parsed as opaque tokens rather than Sass expressions.

For the CSS side of this, see CSS custom properties and media queries.