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:
- Sass variables act as compile-time constants, perfect for immutable brand guidelines and mathematical foundations.
- CSS custom properties serve as runtime-adjustable variables, enabling live theming, CMS overrides, and user-facing customisation. I think this dichotomy shows part of modern web development’s dual demands: rigid design system governance paired with flexible contextual adaptation. Whether you’re building a WordPress theme that content editors can tweak or an SaaS platform requiring dark mode, understanding this split can help unlock smarter architectural decisions.
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 ❤️).