Looking for a Front-End Developer and Design Systems Practitioner?

I currently have some availabilty. Let's talk!.

Always Twisted

CSS Custom Properties vs. Sass Variables: A Pragmatic Guide

On This Page:

In recent articles I’ve demonstrated how we can use Design Tokens to assist with theming, be it for a multi-brand Design System or a single property that has multiple themes.
If you noticed, for the multi-brand configuration we were also generating Sass variables, but it in the second article on creating multiple themes for a single site we weren’t. I have reasons for that, as part of a strategy of when and how I use CSS custom properites or Sass variables that I’ve been implementing and refining over the last 7/8 years. I thought it would make a nice little article, so here goes.

Sass Variables, CSS Custom Properties, What’s the Difference?

CSS custom properties and Sass variables can seem interchangeable at first glance, but I think they excel when we look at their diverging strengths:

When I Use CSS Custom Properties

CSS custom properties are indispensable when dealing with values that can or need to adapt after the page loads. Their inherent runtime flexibility can help solve specific problems static preprocessor variables just cannot touch.

Dynamic Scenarios

Browser runtime changes

If you have things that can update the page live without requiring a page refresh - use CSS custom properties. Great when toggling light/dark mode or changing the overtall theme.

User interaction

Perhaps you have some UI the user can change that effects part of the page. Changing the value of the custom property feels cleaner, and more intuitive.

CMS/Back-End control

Have you got variants or things that you’re wanting the content creators of your site to change but don’t want to add a load of classnames or restrict the variants too much. Choose the value and create the custom property on the back-end that gets used in the browser.

Media query overrides

Simplify responsive logic. Instead of redeclaring margins at breakpoints using CSS custom properties can create cleaner, more logical code.

Design System Use Cases

Theme variables

Maintain consistency while permitting exceptions. --color-background: var(⁠--color-background-primary); ensures brand alignment, but individual components can locally override it via ⁠:where(.alert) { --color-background: var(--color-background-warning; } without side effects.

Runtime computations

Create relationships between values. ⁠--icon-size: calc(var(--font-size) * 1.2); could keep icons proportionally sized to text, even when users adjust font scaling.

Component-level overrides

Enable safer customisation. A ⁠card component uses ⁠—card-shadow internally, allowing specific instances to deviate from the global shadow system without Frankenstein CSS (⁠.card--special { box-shadow: ... }).

When I Use Sass Variables

Immutable Foundations

Brand Enforcement

Sass variables can help lock down design decisions that should never bend. That signature brand blue isn't just a colour – it's ⁠$brand-blue: #2e5eaa; screaming "this stays put" through all of the components and layout templates being used.

Precision Math Systems

Spacing scales become architectural blueprints with Sass's compile-time calculations. While CSS variables futz with ⁠calc() at runtime, Sass resolves ⁠$spacing-unit * 1.5 during build – outputting clean values that can render identically in legacy IE and Chrome Canary. Although this is increasingly a moot point when wanting fluid changes across browser sizes.

Build-Time Power Plays

Utility Class Factories

Need to provide your design decisions as utility classes? Sass loops can help with that (although, if you’re implementing Design Tokens you can generate these using something like Style Dictionary (I will be working on an anrticle about this as part of my Design Tokens Workflow Series soon.

Design System Bedrock

Breakpoint Clarity

Until ⁠@custom-media matures and gets into browsers, Sass variables help to tame responsive chaos.

Performance-Critical Math

If you have a lot of scales for things like spacing, typography or colour perhaps you don’t want the browser to make those calculations if they’re not going to change. Using Sass will help with any possible performance issues of an over reliance on CSS custom properties for everything.

Hard-Coded Themes

When light/dark mode gets decided at build time (CMS page type, A/B test group), Sass maps can generate lean CSS. Sass variables thrive when values need to be set in stone after compilation. They're the mason's chisel – uncompromising, precise, and leaving no runtime debris.

Combining Both With A Hybrid Approach

CSS custom properties and Sass variables aren't sworn enemies – they' can be great collaborators in a layered architecture. This hybrid model can treat Sass as the source of truth and CSS variables as the delivery mechanism for runtime flexibility and at the same time allow you to “set things in stone” that will never change in Sass. Layered Architecture

Layer Purpose Example
Sass Layer Compile-time constants ⁠$gap: 1.125rem;
CSS Layer Runtime-adjustable variables ⁠--component-spacing: #{$gap};

A Decision Tree

This isn’t about right vs. wrong – it’s about matching the tools to the needs of the design, the team, and the product. This table isn’t perdurable and it can and does change from project to project depending on requirements I find it useful to go through at times.

Factor CSS Custom Property Sass Variable
Runtime changes
CMS exposure
Theming Limited
Math operations Basic (⁠calc()) Advanced
Browser support IE11+ (with polyfills) Universal

(although this is ususally thought through rather than checking an actual table).

Final Thoughts

The interplay between Sass variables and CSS custom properties should be a strategic partnership. Over nearly a decade of evolving web practices, one truth persists: robust systems balance rigidity with adaptability. Sass anchors the immutable, CSS custom properties breathe life into any required fluidity.

Resilient systems should layer these tools intentionally. Let Sass handle the the design decisions that won’t change, heavy math and legacy support, while CSS variables manage any dynamicism required.

As browsers advance, the lines may blur – but the principles endure. Choose Sass for what must and should stay fixed, CSS for what needs to change.

After all, the best architectures aren’t built with tools, but with informed decisions about when to wield them.

(a little thanks for Andy Bell for a little 'sense checking' along the way ❤️).

Unsure how to structure your design tokens for scalability and future growth?

I can help define a scalable structure for your tokens, ensuring they grow with your system.

get in touch!