CSSLesson 11 of 12

CSS Variables

CSS variables, officially called CSS custom properties, store values you can reuse. Define --brand once, use var(--brand) anywhere, and change one line to update every use. That turns scattered hard-coded colors into a single source of truth, which is a huge relief when a client asks for a different shade of blue.

CSS variables, officially called CSS custom properties, store values you can reuse. Define --brand once, use var(--brand) anywhere, and change one line to update every use. That turns scattered hard-coded colors into a single source of truth, which is a huge relief when a client asks for a different shade of blue.

Variables follow the cascade and inheritance. Define them on :root and every element can read them. Override them on a smaller container and only that subtree changes. That is exactly how a dark theme works: the theme class redefines the variables, and every component that uses them updates instantly.

You can store more than colors. Spacing, border radius, shadow values, and font sizes all work. One limit to remember: variables are resolved when the browser applies styles, so you cannot use them inside a media query condition. Use them for values, not for logic.

Defining and using variables

Define variables on :root, the top-level element, so every element inherits them. Read them with var(). A fallback is a second argument: var(--brand, #0891b2) uses the fallback if the variable is undefined, which matters when variables are missing or typos creep in. Custom properties are real properties, so they cascade and can be overridden like any other.

CSS
:root {
  --brand: #0891b2;
  --space: 16px;
}

h1 {
  color: var(--brand, #0891b2); /* fallback after the comma */
}

.card {
  padding: var(--space);
}

Scoped overrides for themes

Because variables inherit, overriding them on a container re-themes that whole subtree. A .dark class on the body redefines --bg and --text, and every component using var(--bg) updates instantly. That is a complete theme swap in a few lines. The same trick drives per-component accents: a card that redefines --brand gets its own color while everything else stays put.

CSS
:root {
  --bg: #ffffff;
  --text: #0f172a;
}

.dark {
  --bg: #0f172a;
  --text: #f8fafc;
}

body {
  background: var(--bg);
  color: var(--text);
}

What variables cannot do

Variables are resolved when the browser applies styles, so conditions that run at parse time reject them. You cannot write a media query condition that reads a variable. You also cannot animate var() directly, though you can switch the value the animation reads. Keep variables for values and fallbacks ready, and the limits will rarely touch you.

CSS
/* this does not work: the condition cannot read a variable */
/* @media (min-width: var(--breakpoint)) { ... } */

Syntax

CSS
:root {
  --brand: #0891b2;
  --bg: #f8fafc;
}

body {
  background: var(--bg);
  color: var(--brand);
}

var(--x) Can't Be Used in Media Query Condition

CSS variables work for values, but @media (min-width: var(--bp)) is invalid — conditions are parsed before variables.

CSS
/* BAD */ @media (min-width: var(--bp))

Good to know

  • Define variables on :root so every element can use them.
  • Read them with var(--name) and add a fallback after a comma.
  • Overriding variables on a container re-themes that subtree.
  • Variables hold values, not logic; media query conditions reject them.
Try it Yourself Edit the code, press Run, then check what changed in the Result.
Ready
Code
Result

Practice makes it stick

Open the Playground and build your own page with the tags you just learned.

→ Open Playground