devnotes.

Declaring and Using Variables

CSS custom properties (commonly called CSS variables) let you store a value once and reuse it throughout a stylesheet, updating every usage by editing a single line.

:root {
  --primary-color: #3357ff;
  --spacing-unit: 8px;
  --font-heading: "Georgia", serif;
}

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

.card {
  margin: calc(var(--spacing-unit) * 2);
  border: 1px solid var(--primary-color);
}
  • Custom properties are declared with a -- prefix and read with the var() function.
  • :root is a pseudo-class matching the document's root element (<html>), making variables declared there globally available to every element on the page.
  • calc() combines variables with math operations — here doubling the spacing unit — and can mix units (calc(100% - 20px) is a very common pattern for full-width elements with fixed padding).

Fallback values protect against a variable being undefined:

.box {
  color: var(--text-color, black); /* uses black if --text-color isn't defined */
}

Critically, unlike Sass/LESS preprocessor variables (which are compiled away before the browser ever sees them), CSS custom properties are live in the browser — they can be read and changed by JavaScript at runtime, and they respect the normal cascade, meaning a variable can be redefined inside a specific selector to change its value only within that scope:

.dark-section {
  --primary-color: #66aaff; /* overrides the global value, only within .dark-section */
}

This scoping behavior — impossible with preprocessor variables — is what makes CSS custom properties especially powerful for theming, covered next.