Codectionary / Developer documentation / CSS

Custom Properties (CSS Variables)

Custom properties, written as --name, let you define reusable values directly in CSS, accessed with var(). Unlike Sass variables, they are live in the browser - they can be read and changed with JavaScript, and they respect the cascade, meaning their value can be different in different parts of the DOM.

Syntax

--name: value;
var(--name, fallback);

Examples

Defining and Using Variables

A typical theming setup using custom properties on :root.

/* Demo setup: sizing, structure or neutral surfaces. */
.button{border:0;min-height:3rem}

:root {
  --primary-color: #3b82f6;
  --spacing-unit: 8px;
  --border-radius: 6px;
}

.button {
  background: var(--primary-color);
  padding: calc(var(--spacing-unit) * 2);
  border-radius: var(--border-radius);
}
  1. The button’s values are read from custom properties rather than copied into every declaration.
  2. A closer scope can override a token while another element keeps the root value.
  3. Change the root token or the scoped override and rerun to see which controls inherit the result.
HTML used by this example
<button class="button">Study plan action</button>

Scoped Overrides and Fallbacks

Custom properties respect the cascade, so they can be overridden in specific contexts.

/* Demo setup: sizing, structure or neutral surfaces. */
:root{--primary-color:#c2410c}.button{background:var(--primary-color);padding:1rem;border:0;margin:1rem}.dark-theme{background:#1e293b;padding:1rem}

.dark-theme {
  --primary-color: #60a5fa; /* overrides the root value just within this scope */
}

.button {
  color: var(--text-color, black); /* falls back to black if --text-color is not defined */
}
  1. The button’s values are read from custom properties rather than copied into every declaration.
  2. A closer scope can override a token while another element keeps the root value.
  3. Change the root token or the scoped override and rerun to see which controls inherit the result.
HTML used by this example
<button class="button">Root scope</button><section class="dark-theme"><button class="button">Overridden scope</button></section>

Parameters and values

  • --name: value; (declaration): Defines a custom property, commonly on :root for global scope
  • var(--name) (function): Reads a custom property's current value
  • var(--name, fallback) (function): Uses a fallback if the custom property is not defined

Best practices

  • Define global theme variables on :root, and override them locally on specific components or contexts (like a .dark-theme class) as needed
  • Provide a fallback value in var() for properties that might not always be defined, like var(--gap, 1rem)
  • Take advantage of custom properties being live and JavaScript-readable for dynamic theming without regenerating an entire stylesheet
  • Use meaningful, consistent naming conventions (--color-primary, --spacing-sm) as a project grows, similar to a design token system

Browser compatibility

chrome
Yes
firefox
Yes
safari
Yes
edge
Yes

These are the existing reference’s support labels, not tested minimum versions. Individual values and APIs can have different support. Check the linked specification before choosing a browser target.

CSS specifications (modules)

Specifications & further reading