Skip to content

CSS Custom Properties: A Practical Approach to Theming

Sass variables are compiled away at build time. CSS custom properties live in the browser, cascade like any other property, and can be changed at runtime. That difference matters more than most developers realise.

MI

mubashar

· 1 min read
Share

I switched from Sass variables to CSS custom properties about three years ago and haven't looked back. The runtime behaviour is the feature — you can't do dark mode, theme switching, or component-level overrides cleanly with Sass variables alone.

The Key Difference From Sass Variables

Sass variables are a preprocessor feature. They get compiled to static values before the browser ever sees them. $brand-blue becomes #3B82F6 in the output CSS. You can't change a Sass variable at runtime, in a media query, or per component.

CSS custom properties cascade and inherit like any other property. Define them on :root and they're available everywhere. Override them on a specific selector and everything inside that element gets the override.

Setting Up a Token System

Put all your design tokens on :root:

:root {
  --bg-base: #0F172A;
  --clr-primary: #3B82F6;
  --text-body: #E2E8F0;
}

To retheme the entire site, change the values in :root only.

Dark Mode Without a Class Toggle

With CSS custom properties, dark mode requires almost no JavaScript:

:root { --bg: #ffffff; --text: #111827; }
@media (prefers-color-scheme: dark) {
  :root { --bg: #0F172A; --text: #E2E8F0; }
}

Every element that uses var(--bg) automatically switches. No JavaScript class toggling required.

Component-Level Overrides

The cascade makes per-component theming clean. A card component might define its own surface colour, overriding the global token only within its scope.

MI

Written by

Mubashar Iqbal

Web developer, SEO expert, and independent maker. I build products, write about what I've learned, and create free tools for developers and marketers.