sodcalculator

10 Tech How-To

CSS Variables: How to Use Them With Examples

Guide 10-40971 · Updated · Step by step

CSS variables, officially called custom properties, let you store reusable values such as colors, spacing, and font sizes, then reference them throughout a stylesheet with var(). Define a property with a name beginning --, usually on :root, and use it wherever a CSS value is accepted; you can also override it for a particular component or theme.

What CSS Variables Are

A custom property is a CSS declaration whose name starts with two hyphens. Unlike a preprocessor variable, it is part of the browser’s CSS and remains available to the page at runtime. This means its value can respond to the cascade, inheritance, media queries, and JavaScript changes.

For example, a site may use the same accent color on links, buttons, and borders. Defining it once makes later changes easier and reduces mismatched values:

:root {
  --color-accent: #1769aa;
}

.button {
  background-color: var(--color-accent);
}

a {
  color: var(--color-accent);
}

The double hyphen is required for ordinary custom properties. Names are case-sensitive, so --main-color and --Main-color are different properties. Choose descriptive names that explain a role or purpose rather than a temporary appearance.

How to Define and Use a Variable

Declare a custom property inside a rule, then substitute it with var(--name). The property does not need a special declaration type: its value is stored as a token sequence and interpreted when used in a regular CSS declaration.

:root {
  --page-width: 68rem;
  --space: 1rem;
  --text-color: #242424;
}

main {
  max-width: var(--page-width);
  margin-inline: auto;
  padding: var(--space);
  color: var(--text-color);
}

Here, :root selects the document’s root element, which is usually html. A property defined there can inherit through the document, making it a practical location for site-wide design values. You may define properties in any selector, however; they apply to that element and descendants that inherit them.

Custom properties do not automatically represent a specific data type. The value 1rem can be used as a length, while a value like solid can be used as part of a border declaration. The browser checks whether the substituted result makes sense for the property where it is used.

Fallbacks, Scope, and Inheritance

var() accepts an optional fallback after a comma. The fallback is used when the referenced custom property is missing or has an invalid value for that use:

.notice {
  color: var(--notice-color, #7a3b00);
}

The fallback is not a general repair mechanism for every invalid declaration. If --notice-color exists but expands to a value that is invalid for color, the browser does not necessarily substitute the fallback; the consuming declaration becomes invalid at computed-value time. Ensure the defined value has the right form, or use a fallback for the case where the property is absent.

Scope makes component-level customization possible. A local value overrides an inherited value for that component and its descendants:

:root {
  --button-bg: #1769aa;
}

.button--warning {
  --button-bg: #a33b20;
}

.button {
  background: var(--button-bg);
}

A warning button gets its local color without changing the default for other buttons. Custom properties normally inherit, so a descendant can use a value declared on an ancestor unless a closer rule overrides it.

Practical Examples: Themes and Repeated Values

Variables are useful for related design tokens: colors, spacing scales, border radii, and typography. Keeping these values together makes a stylesheet easier to adjust consistently.

:root {
  --surface: #fff;
  --text: #222;
  --accent: #1769aa;
  --radius: 0.5rem;
}

.card {
  color: var(--text);
  background: var(--surface);
  border-radius: var(--radius);
}

.card a {
  color: var(--accent);
}

.dark-theme {
  --surface: #202124;
  --text: #f1f3f4;
  --accent: #8ab4f8;
}

Applying dark-theme to a container changes the values inherited by its contents. This approach can support a theme switch without duplicating every component rule. The theme still needs suitable contrast and should be tested across the elements that use these tokens.

You can also use variables in calculations, provided the combined value is valid:

:root {
  --gap: 0.75rem;
}

.grid {
  gap: calc(var(--gap) * 2);
}

When mixing different units, CSS math functions may need explicit compatible units or a valid calculation. A bare number and a length do not mean the same thing: for example, --scale: 2 is unitless, while --gap: 2rem is a length.

CSS Variables Compared With Sass Variables

Sass variables, such as $primary, are processed by a build tool before the CSS reaches the browser. They are useful for compile-time calculations and generating styles, but the browser does not receive the Sass variable itself.

CSS custom properties are delivered in the stylesheet and can change at runtime through the cascade. They can vary by selector, respond to media queries, and be updated with JavaScript. They are not a complete replacement for Sass: a project may use Sass for build-time features and custom properties for values that need to vary in the browser.

Common Problems and Good Practices

  • Missing the two hyphens: color: accent is not a variable reference. Declare --accent and use var(--accent).
  • Using the wrong scope: a property defined on one component is not automatically available to an unrelated element. Put shared values on a common ancestor such as :root.
  • Assuming variables are typed: the browser stores the value, but the consuming property still requires a valid value. A length cannot serve as a color.
  • Forgetting inheritance: a local declaration can change what descendants receive. Inspect the computed styles and the element’s ancestors when a value looks unexpected.
  • Overusing generic names: names such as --blue describe a color, not its purpose. A role-based name like --color-link is easier to maintain when the design changes.

Custom properties can also form cycles, such as two variables referring to each other. A cyclic value is invalid, so keep dependencies straightforward. For debugging, check the browser’s developer tools for the computed custom property and the final declaration that uses it.

Frequently Asked Questions

Do CSS variables work in all modern browsers?
CSS custom properties are supported by current mainstream browsers. If a project must support older browsers, check its specific support requirements and provide an appropriate fallback strategy.

Can I use CSS variables in media queries?
You can change a custom property inside a media query and use that changed value in ordinary declarations. However, custom properties cannot generally be substituted into media-query conditions themselves.

Can JavaScript change a CSS variable?
Yes. JavaScript can set a custom property on an element’s style, for example with element.style.setProperty('--accent', 'teal'). The value then participates in the cascade for that element.

Why is my var() value not working?
Check the spelling and capitalization, whether the variable is in scope, and whether its value is valid for the CSS property using it. A fallback can cover a missing variable, but it does not fix every invalid substituted value.

Can a CSS variable store a whole declaration?
A custom property stores a sequence of tokens, not a complete declaration that can be inserted as a block of CSS. You can store a value used within a declaration, such as a color or part of a calculation.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →