Imagine changing your brand colour in one place and watching the whole site update. That is what CSS variables (custom properties) give you. They are the foundation of theming and design systems.
Declaring and using variables
Declare a variable with a <code>--name</code> and use it with <code>var(--name)</code>. They are usually declared on <code>:root</code> so they are available everywhere.
:root { --brand: #2563eb; }- Scope
:root - Variable
--brand - Value
#2563eb
<button class="btn">Brand button</button>
<p class="link">Brand text</p>:root{--brand:#2563eb;--space:16px}
.btn{background:var(--brand);color:#fff;border:0;padding:var(--space);border-radius:8px}
.link{color:var(--brand)}Why variables matter
Variables remove repetition and make global changes trivial. Define your colours, spacing and font sizes once as variables, and your CSS becomes consistent and easy to maintain — exactly how design systems work.
Scoping and fallbacks
Variables cascade and can be overridden on any element, which is how component variants and dark mode work. <code>var(--x, fallback)</code> provides a default if the variable is not set.
<div class="card">Scoped</div>
<div class="card alt">Overridden</div>:root{--bg:#dbeafe}
.card{background:var(--bg);padding:16px;margin-bottom:8px;border-radius:8px}
.alt{--bg:#fde68a}.a{color:#2563eb}.b{color:#2563eb}
.c{border-color:#2563eb}:root{--brand:#2563eb}
.a,.b{color:var(--brand)}
.c{border-color:var(--brand)}Repeating the same colour hex dozens of times. When the brand changes, you must hunt them all down. Use a variable.
Define a small set of variables for colours, spacing and font sizes at :root. This is the first step toward a design system — which you will build fully at the senior level.
Define --brand and --space variables on :root, then build a button and a card that both use them. Change the variable values and watch everything update at once.
1. How do you declare a CSS variable?
2. How do you use one?
3. Where are variables usually declared globally?
- Declare variables with --name (usually on :root) and read with var().
- They remove repetition and enable global changes.
- Variables cascade and can be overridden — the basis of theming.
- var(--x, fallback) provides a default.