Skip to content

Sass and CSS Custom Properties

Sass variables and CSS custom properties (var(--name)) solve related but different problems. This lesson clarifies the distinction and shows how to generate runtime-themeable custom properties from a compile-time Sass token map.

Sass Variables vs CSS Custom Properties

A Sass variable ($primary) is resolved once, at compile time, and never exists in the browser. A CSS custom property (--primary) is a real, live browser feature that can be read, overridden, and changed at runtime, including through JavaScript or a media query like prefers-color-scheme.

$primary: #2563eb; // Sass variable: compile-time only

:root {
  --primary: #{$primary}; // CSS custom property: exists at runtime
}

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

The Sass variable seeds the custom property's initial value; from that point forward, var(--primary) can be overridden live in the browser.

Generating Custom Properties From Sass

:root {
  --name: #{$sass-variable};
}

.element {
  property: var(--name, fallback-value);
}
  • Interpolation (#{}) is required to output a Sass variable's value as a custom property's value.
  • var(--name) reads a custom property; a second argument provides a fallback if it's undefined.
  • Custom properties cascade and can be overridden at any level, unlike Sass variables, which are resolved once.
  • Custom properties can be changed with JavaScript (element.style.setProperty()) for real runtime theming.

Sass Variables vs Custom Properties Cheatsheet

When to reach for each approach.

Aspect Sass Variable CSS Custom Property
Resolved when? Compile time Runtime, in the browser
Exists in output CSS? No Yes
Can change without recompiling? No Yes
Supports media query overrides? No Yes, e.g. dark mode
Supports JavaScript updates? No Yes
Best for Build-time logic, computation, loops Runtime theming, user-toggled preferences

Generating a Full Theme as Custom Properties

Combine a Sass token map with a loop to generate a complete set of runtime-overridable custom properties in one pass, exactly the pattern introduced briefly in the Design Tokens lesson.

$colors: (primary: #2563eb, success: #16a34a, danger: #dc2626);

:root {
  @each $name, $value in $colors {
    --color-#{$name}: #{$value};
  }
}

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

Runtime Theme Switching With Custom Properties

Because custom properties live at runtime, a [data-theme="dark"] selector (or a prefers-color-scheme media query) can override the same variable names without recompiling any Sass, enabling instant theme switches.

:root {
  --color-bg: white;
  --color-text: #1f2937;
}

[data-theme="dark"] {
  --color-bg: #0f172a;
  --color-text: #f1f5f9;
}

body {
  background: var(--color-bg);
  color: var(--color-text);
}

When to Use Sass Variables vs Custom Properties

Use Sass variables for anything that only needs to exist during compilation, math, loops, mixin logic. Use CSS custom properties for anything a user or a runtime script needs to be able to change without a rebuild, most commonly theme colors and spacing.

Common Mistakes

  • Trying to use a Sass variable for runtime theming, which is impossible since it's already resolved before the CSS ships.
  • Forgetting interpolation (#{}) when outputting a Sass variable's value into a custom property declaration.
  • Not providing a fallback value in var(--name, fallback) for custom properties that might not always be defined.
  • Generating dozens of custom properties for values that will genuinely never need runtime overriding, adding unnecessary indirection.

Key Takeaways

  • Sass variables are compile-time only; CSS custom properties exist and can change at runtime in the browser.
  • Generate custom properties from a Sass token map using interpolation inside a loop.
  • Custom properties enable real theme switching through selectors, media queries, or JavaScript.
  • Choose Sass variables for build-time logic and custom properties for anything needing runtime flexibility.

Pro Tip

Reserve CSS custom properties for values that genuinely need runtime flexibility, theme colors, user preferences, mostly everything else (spacing scales, breakpoints, one-off calculations) can safely stay as compile-time Sass variables with zero runtime cost.