MODULE 03 · CSS FOUNDATIONS

Custom Properties & Variables

Repeating the same color or size across dozens of rules is fragile — change your mind once and you're hunting through the whole stylesheet. Custom properties let you define a value once and reuse it everywhere.

Day 23 of 30 Beginner ~17 min

A Value You Define Once, Use Everywhere

A CSS custom property — often just called a "CSS variable" — stores a value under a name you choose, prefixed with two dashes. Reference it anywhere with var(), and if you ever need to change that value, you change it in exactly one place.

--name and var()

Declare a custom property on :root so it's available globally, then reference it with var() anywhere you'd normally write a literal value.

style.css
:root {
  --brand-orange: #e8590c;
  --brand-ink: #12141c;
  --radius-md: 12px;
}

.btn {
  background: var(--brand-orange);
  color: white;
  border-radius: var(--radius-md);
}

.heading {
  color: var(--brand-ink);
}
WHY :root?

:root targets the <html> element with slightly higher specificity — it's the conventional place to define global custom properties so they cascade down to every element on the page.

A Second Argument for var()

var() accepts an optional second argument — a fallback used if the custom property isn't defined. This is especially useful for reusable components that might be dropped into a page without every variable set up.

style.css
.chip {
  /* uses --custom-set if defined, else falls back to orange */
  background: var(--custom-set, var(--orange));
}
DEFINED VS UNDEFINED VARIABLE
--custom-set: defined --custom-unset: falls back

Redefining a Variable Inside a Component

Custom properties follow the cascade like any other CSS. Redeclare the same variable name on a child element or a class, and everything inside that scope picks up the new value — without touching the original component's rules.

style.css
.token-card {
  --card-bg: #fff1e6;
  --card-ink: #b8430a;
  background: var(--card-bg);
  color: var(--card-ink);
}

/* same component, different theme — no duplicated rules */
.token-card.theme-b {
  --card-bg: #fff0f5;
  --card-ink: #c2447a;
}
SAME COMPONENT, THREE OVERRIDDEN THEMES

Default

Orange token set.

Theme B

Pink token set.

Theme C

Indigo token set.

Not the Same Thing

If you've heard of Sass or LESS variables, custom properties look similar but behave differently underneath.

ASPECT DIFFERENCE
When resolved

Sass variables compile away before the browser sees them; CSS custom properties stay live at runtime.

Cascade

Custom properties inherit and can be overridden per element, just like any other CSS property.

Media queries

Custom properties can be redefined inside a media query to swap values responsively.

Build a Small, Consistent System

GOOD VS UNHELPFUL NAMING
AVOID Naming variables after the value itself, like --orange or --16px — if the color changes, the name becomes misleading.
BETTER Name by purpose: --brand-primary, --radius-md, --spacing-lg — the name stays accurate even if the value changes.

Breaking Down What You Just Learned

1

Declare and read--name: value; declares a custom property; var(--name) reads it back.

2

Global scopeDeclaring variables on :root makes them available to every element on the page.

3

Fallbacksvar(--name, fallback) supplies a backup value if the variable isn't defined.

4

Scoped overridesRedeclaring a variable on a class swaps its value for everything inside that scope.

5

Name by purposePurpose-based names like --brand-primary stay accurate even as the underlying value changes.

Try It Yourself

EXERCISE

Take a page from earlier in the course and pull every repeated color and spacing value into :root custom properties. Then create a second "theme" class that overrides just the color variables on one section.

Build a Token-Driven Component

HANDS-ON EXERCISE

Practicing custom properties end to end

Create day23.html linked to a stylesheet and build the following on the page.

  1. Define --brand-primary, --brand-ink, and --radius-md on :root.
  2. Build a card component that uses all three variables via var().
  3. Duplicate the card and add a .theme-alt class that overrides just the color variables.
  4. Use var() with a fallback value on one property that isn't defined anywhere.
  5. Confirm changing a single :root value updates every element that references it.

Recap

DECLARE & READ

--name: value; declares a variable; var(--name) reads it wherever a value is needed.

GLOBAL SCOPE

:root is the conventional place to define variables shared across the whole page.

FALLBACKS

A second argument to var() supplies a backup if the variable is undefined.

SCOPED OVERRIDES

Redeclaring a variable on a class swaps its value for just that scope.

Key Takeaways

  • Custom properties are declared with -- and read with var(), storing a value once for reuse everywhere.
  • :root is the standard place to define variables meant to be shared across an entire page.
  • var() accepts an optional fallback value as its second argument.
  • Redeclaring the same variable name inside a narrower scope overrides it for that scope only — the cascade still applies.
  • Unlike Sass variables, custom properties are live in the browser and can update responsively or via JavaScript.
Course Overview