✦ A decade of Canvas craft, now driven by AI, describe it, watch it build live.Start building
Glossary

What Is CSS Custom Properties?

CSS Custom Properties, formally defined in the CSS Custom Properties for Cascading Variables Module Level 1 specification (W3C), are developer-defined variables declared with a double-hyphen prefix (--variable-name) that store reusable values like colors, spacing, or font sizes directly in the CSS cascade. Unlike preprocessor variables (Sass, Less), they are live in the DOM, meaning JavaScript can read and update them at runtime without recompilation. They inherit through the document tree, follow specificity rules, and can be scoped to specific elements or globally via the :root pseudo-class.

What Is CSS Custom Properties?

CSS Custom Properties, formally defined in the CSS Custom Properties for Cascading Variables Module Level 1 specification (W3C), are developer-defined variables declared with a double-hyphen prefix (--variable-name) that store reusable values like colors, spacing, or font sizes directly in the CSS cascade. Unlike preprocessor variables (Sass, Less), they are live in the DOM, meaning JavaScript can read and update them at runtime without recompilation. They inherit through the document tree, follow specificity rules, and can be scoped to specific elements or globally via the :root pseudo-class.

How CSS Custom Properties Works

CSS Custom Properties are declared using a double-hyphen prefix inside a selector block, such as :root { --primary-color: #3b82f6; }, and consumed using the var() function: color: var(--primary-color, #000);. The second argument inside var() is a fallback value, which the browser uses when the property is undefined or invalid at that scope. This fallback mechanism is part of the specification and is critical for building resilient component systems where not every context guarantees a variable is defined. Inheritance is a core behavior: a custom property defined on a parent element is accessible to all its descendants in the DOM tree, behaving exactly like inherited CSS properties. This means you can define a component-level variable on a card component's root element, override it in a specific variant, and every child element within that component picks up the correct value without any additional selectors. This scoping behavior is fundamentally different from Sass variables, which resolve at compile time and produce static output. Custom properties participate fully in the CSS cascade, meaning they can be overridden by media queries, pseudo-classes, and specificity just like any other CSS declaration. A common pattern is redefining variables inside a @media (prefers-color-scheme: dark) block on :root to implement dark mode without touching any component-level selectors. The browser recomputes all dependent properties automatically when a custom property changes, whether triggered by a media query or a JavaScript assignment via element.style.setProperty('--primary-color', '#ef4444'). The computed value of a custom property is always a string; the browser substitutes the variable's value into the declaration before computing types. This means var(--spacing) can be used in calc() expressions like calc(var(--spacing) * 2), making mathematical relationships between design tokens expressible in pure CSS. Browser support is universal across all modern browsers as of the CSS Custom Properties Level 1 spec, and no polyfill is needed for production use today.

Best Practices for CSS Custom Properties

Define all global design tokens (colors, typography scales, spacing units, border radii, box shadows) as custom properties on :root so every component in a project reads from a single source of truth, making global rebranding a matter of changing variable values rather than hunting through stylesheets. Always provide fallback values inside var() for any property that may be conditionally defined, especially in component libraries consumed by third parties. Use semantic naming conventions like --color-brand-primary instead of --blue-500 so the variable name describes its purpose rather than its current value, allowing the underlying value to change without the name becoming misleading. Scope component-specific overrides to the component's own selector rather than :root to avoid polluting the global namespace; for example, define --card-padding on .card rather than globally, and use CSS inheritance to let child elements pick it up without explicit declarations.

CSS Custom Properties & Canvas Builder

Canvas Builder produces Bootstrap 5 HTML output, and Bootstrap 5 is architected around CSS Custom Properties for its color palette, grid gutters, component spacing, and typography, meaning every site Canvas Builder generates inherits a structured custom property system out of the box. The clean, semantic markup Canvas Builder outputs avoids the inline style overrides and div-soup that make custom property scoping difficult, so developers can apply component-level variable overrides to predictable, well-named selectors. Teams using Canvas Builder as a starting point can extend the generated codebase with a design token layer by simply augmenting the :root declarations, achieving consistent theming across all generated components without modifying the underlying HTML structure.

Try Canvas Builder →

Frequently Asked Questions

Can CSS Custom Properties be animated with CSS transitions or @keyframes?
CSS Custom Properties themselves are not interpolated by the browser during animations because their computed value is always a string, not a typed number or color. However, you can animate properties that consume a custom property by using @property (Houdini's CSS Properties and Values API), which lets you register a custom property with a specific syntax type (like <color> or <length>) so the browser knows how to interpolate it. Without @property registration, a variable swap during an animation will produce an instant jump rather than a smooth transition.
How do CSS Custom Properties differ from Sass variables in practice?
Sass variables are resolved at compile time and output static CSS values, meaning they are gone by the time the browser sees the stylesheet and cannot respond to runtime conditions. CSS Custom Properties exist in the live cascade, so they can be changed by JavaScript, overridden by media queries, or scoped per element without any build step. This makes custom properties the correct tool for theming, dark mode, and dynamic UI state, while Sass variables remain useful for build-time logic like loops, functions, and conditional compilation.
How does Canvas Builder's output work with CSS Custom Properties?
Canvas Builder generates clean, production-ready HTML built on Bootstrap 5, which in its current versions uses CSS Custom Properties extensively for its color system, spacing scale, and component theming. Because Canvas Builder outputs semantic, well-structured HTML without inline style clutter, developers can layer a custom :root variable block on top of the generated output to retheme an entire site by overriding Bootstrap's own custom property tokens like --bs-primary or --bs-font-size-base. This means sites built with Canvas Builder are immediately ready for systematic design token customization without restructuring any generated markup.