CSS Variables

CSS variables, formally called custom properties, allow you to define reusable values and reference them throughout a stylesheet. They are useful for colors, spacing, font sizes, dimensions, and other values that appear repeatedly in a design.

Custom properties use names beginning with two hyphens, such as --primary-color. The stored value is retrieved with the var() function wherever that custom property can be used.

Why Use CSS Variables

Without custom properties, the same value may need to be repeated throughout a stylesheet.

.header {
  background-color: #0088cc;
}
.button {
  background-color: #0088cc;
}
.link {
  color: #0088cc;
}

If the color changes, every declaration containing that value may need to be updated.

A custom property allows the value to be defined once and reused.

:root {
  --primary-color: #0088cc;
}
.header {
  background-color: var(--primary-color);
}
.button {
  background-color: var(--primary-color);
}
.link {
  color: var(--primary-color);
}

Changing --primary-color can then update all declarations that reference it.

Declaring CSS Variables

A custom property name begins with two hyphens followed by a name chosen by the stylesheet author.

--primary-color: #0088cc;

Like other CSS declarations, a custom property must be declared inside a CSS ruleset.

:root {
  --primary-color: #0088cc;
  --text-color: #333;
  --spacing: 20px;
}

Custom property names are case-sensitive. For example, --primary-color and --Primary-Color are different custom properties.

Using var()

The var() function retrieves the value stored in a custom property.

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

The custom property name is placed inside the parentheses and must include its two leading hyphens.

Custom properties can be reused by many different CSS properties when the stored value is valid for those properties.

.card {
  color: var(--text-color);
  padding: var(--spacing);
  border-color: var(--primary-color);
}

The browser substitutes the computed custom property value where the var() function is used.

Global Variables with :root

The :root pseudo-class represents the document's root element. In an HTML document, this is the <html> element.

:root {
  --primary-color: #0088cc;
  --secondary-color: #02bf57;
  --text-color: #333;
}

Custom properties declared on :root are commonly used as site-wide values because custom properties normally inherit to descendant elements.

body {
  color: var(--text-color);
}
a {
  color: var(--primary-color);
}
.button {
  background-color: var(--secondary-color);
}

Using :root does not make a custom property a special type of variable. It simply places the declaration high in the document tree where it can be inherited by elements throughout the page.

Local Variables

Custom properties can also be declared on individual selectors instead of :root.

.card {
  --card-color: #006699;
  color: var(--card-color);
}

In this example, --card-color is defined on elements matching .card. It is available to the element and can normally be inherited by its descendants.

.card {
  --card-color: #006699;
}
.card h2 {
  color: var(--card-color);
}

Local custom properties are useful when a value belongs to a particular component rather than the entire website.

Variable Inheritance

Custom properties declared with the standard two-hyphen syntax normally inherit from a parent element to its descendants.

.article {
  --heading-color: #005580;
}
.article h2 {
  color: var(--heading-color);
}

The <h2> does not declare --heading-color itself. It receives the custom property through inheritance from the element matching .article.

If a descendant declares the same custom property, that declaration can provide a different value within that part of the document.

.article {
  --heading-color: #005580;
}
.special {
  --heading-color: #8b0000;
}

Elements inside .special can then use the new value when they reference --heading-color.

Fallback Values

The var() function can include a fallback value after a comma. The fallback is used when the referenced custom property is not defined or has a CSS-wide keyword in a way that makes the custom property invalid for substitution.

.button {
  background-color: var(--button-color, #0088cc);
}

If --button-color is unavailable for substitution, the browser uses #0088cc.

Fallbacks can also contain another var() function.

.button {
  color: var(--button-text, var(--text-color, #fff));
}

The browser first tries --button-text, then --text-color, and finally #fff if the preceding custom properties cannot provide a usable substitution.

Overriding Variables

Because custom properties participate in the cascade, their values can be changed for particular selectors or parts of a page.

:root {
  --panel-color: #0088cc;
}
.panel {
  background-color: var(--panel-color);
}
.warning {
  --panel-color: #b00020;
}

An element with both panel and warning classes uses the value declared by .warning.

<div class="panel warning">
  Warning Panel
</div>

This makes custom properties useful for themes, component variations, and contextual styling without rewriting every property that uses the value.

Responsive Variables

Custom properties can be reassigned inside media queries. Any declarations using those properties can then respond to the new values.

:root {
  --page-spacing: 16px;
}
.container {
  padding: var(--page-spacing);
}
@media (min-width: 768px) {
  :root {
    --page-spacing: 32px;
  }
}

The container uses 16px of padding initially and 32px when the media query condition is met.

This can reduce repeated responsive declarations when several parts of a design depend on the same changing value.

Naming CSS Variables

Descriptive names make custom properties easier to understand and maintain. Names should describe the purpose of a value rather than where it happens to be used at one moment.

:root {
  --primary-color: #0088cc;
  --body-text-color: #333;
  --content-spacing: 20px;
  --border-radius-small: 4px;
}

A consistent naming system becomes increasingly useful as a stylesheet grows.

Avoid vague names such as --value1 or names that become misleading when a design changes.

CSS Variable Practices

Practice Purpose
Use descriptive names Makes the purpose of reusable values easier to understand.
Use :root for widely shared values Makes site-wide custom properties available through inheritance.
Use local variables for components Keeps component-specific values close to the styles that use them.
Use fallback values when appropriate Provides an alternative when a custom property cannot supply a value.
Take advantage of the cascade Allows themes and component variations to override reusable values.
Avoid unnecessary variables Keeps simple one-time values from making the stylesheet harder to follow.

CSS Variables Example

The following example defines reusable colors and spacing on :root. The same custom properties are then used by several declarations.

:root {
  --primary-color: #0088cc;
  --text-color: #333;
  --spacing: 20px;
}
.card {
  color: var(--text-color);
  padding: var(--spacing);
  border: 2px solid var(--primary-color);
}
.card h2 {
  color: var(--primary-color);
}
.button {
  color: #fff;
  background-color: var(--primary-color);
}

Open the example in the editor and change the values declared in :root. For example, change --primary-color or --spacing and run the example again. Every declaration using that custom property will use the new value.

Play in Editor