JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicscssCSS Custom Properties (Variables)
PrevNext
css
intermediate
10 min read

CSS Custom Properties (Variables)

at-property
custom-properties
dark-mode
design-tokens
sass
theming
variables

CSS custom properties (--variable) are live, cascading values accessed via var() that can be scoped, inherited, overridden at any level, and manipulated with JavaScript at runtime — fundamentally different from preprocessor variables that are static and compiled away.

Key Points

1Cascade and Inheritance

Custom properties participate in the CSS cascade and are inherited by descendants, enabling contextual theming by overriding values at any level in the DOM tree.

2Runtime JavaScript Access

Custom properties exist in the live DOM and can be read with getComputedStyle() and written with setProperty() — enabling dynamic theming and user-driven customization.

3Fallback Values

The var() function accepts a fallback as a second argument, and fallbacks can be nested. If no value or fallback exists, the declaration becomes invalid at computed-value time.

4Preprocessor Variables Are Different

Sass/Less variables are compiled away at build time with no cascade, inheritance, or runtime access. CSS custom properties are live, scoped, and manipulable — they serve different purposes.

What You'll Learn

  • Declare and use CSS custom properties with var() and fallback values
  • Explain how custom properties cascade and inherit through the DOM
  • Compare CSS custom properties with Sass/Less variables and identify when each is appropriate
  • Manipulate custom properties at runtime with JavaScript for dynamic theming

Deep Dive

CSS custom properties (often called CSS variables) are entities defined by authors that contain specific values reusable throughout a document. They participate in the cascade and inheritance, making them far more powerful than preprocessor variables.

Syntax and Basics

Custom properties are declared with a double-hyphen prefix and accessed with the var() function:

CSS
:root {
  --color-primary: #3b82f6;
  --spacing-md: 1rem;
}
 
.button {
  background: var(--color-primary);
  padding: var(--spacing-md);
}

The var() function accepts an optional fallback value: var(--color-primary, blue). Fallbacks can be nested: var(--color, var(--fallback, red)). If the custom property is invalid or not defined and no fallback exists, the property using it becomes invalid at computed-value time.

Cascade and Inheritance

Custom properties cascade and inherit like any other CSS property. A property set on :root is available everywhere. A property set on .card is available to all .card descendants. This enables powerful scoping:

CSS
:root { --color-primary: blue; }
.dark-theme { --color-primary: lightblue; }
.card { background: var(--color-primary); }

A .card inside .dark-theme automatically gets the overridden value without any additional selectors or classes.

Runtime Manipulation with JavaScript

Unlike preprocessor variables, custom properties exist in the live DOM and can be read and written with JavaScript:

JavaScript
// Read
getComputedStyle(element).getPropertyValue('--color-primary');
// Write
element.style.setProperty('--color-primary', '#ef4444');

This enables dynamic theming, user preferences, responsive values driven by JavaScript, and animation targets — all impossible with Sass or Less variables.

CSS Variables vs Preprocessor Variables

| Aspect | CSS Custom Properties | Sass/Less Variables | |--------|----------------------|--------------------| | Runtime | Live in the browser | Compiled away at build time | | Cascade | Participate in cascade and inheritance | Static, no cascade awareness | | Scope | Scoped to any selector, inherited by children | Scoped to block or file | | JavaScript | Readable and writable at runtime | Not accessible at runtime | | Fallbacks | Built-in via var(--prop, fallback) | Requires conditional logic | | Media queries | Can be changed inside @media rules | Cannot change inside @media |

Preprocessor variables are still useful for compile-time constants (like breakpoint values used in @media queries), build-time calculations, and values that never change at runtime.

Common Use Cases

  • Theming — Light/dark mode by overriding variables on a parent element
  • Component variants — Override spacing or color variables per context
  • Responsive design — Change variable values in media queries for global adjustments
  • Design tokens — Map design system tokens to custom properties for a single source of truth
  • Animation — Animate custom properties with @property registration for typed animations

The @property Rule

The @property at-rule registers a custom property with a type, initial value, and inheritance behavior:

CSS
@property --rotation {
  syntax: '<angle>';
  initial-value: 0deg;
  inherits: false;
}

Registered properties can be animated/transitioned, validated by the browser, and given default values — extending custom properties from simple text substitution to typed, animatable values.

Fun Fact

CSS custom properties were originally called 'CSS Variables' in the specification, but the working group renamed them because they behave nothing like variables in programming languages — they cascade, inherit, and can hold any valid CSS value including entire shorthand declarations.

Learn These First

CSS Selectors & Specificity

beginner

Continue Learning

Cascade Layers (@layer)

advanced

Responsive Design Fundamentals

beginner

Practice What You Learned

What are CSS custom properties (variables) and how do they differ from Sass variables?
mid
custom-properties
CSS custom properties (--my-var) are native CSS variables that cascade, can be scoped to selectors, updated at runtime with JavaScript, and inherited by child elements. Sass variables ($my-var) are compile-time only and produce static output. CSS variables enable theming, dark mode, and dynamic styling without preprocessors.
Previous
Container Queries (@container)
Next
Flexbox Layout
PrevNext