Lab 04: CSS Custom Properties

Time: 30 minutes | Level: Practitioner | Docker: docker run -it --rm node:20-alpine sh

Overview

CSS Custom Properties (variables) enable dynamic theming, design tokens, and component-level customization. Learn var() with fallbacks, scoping, JS manipulation, @property registration, and token patterns.


Step 1: Basic var() and Fallbacks

/* Declaration: always starts with -- */
:root {
  --color-primary: #3b82f6;
  --spacing-base: 16px;
  --border-radius: 8px;
  --font-size-base: 1rem;
}

/* Usage: var(--name, fallback) */
.button {
  background: var(--color-primary);
  padding: var(--spacing-base, 1rem);   /* fallback if undefined */
  border-radius: var(--border-radius);
  
  /* Chained fallbacks */
  color: var(--button-color, var(--color-text, #111));
  
  /* Fallback can be any valid value */
  font-size: var(--button-font-size, 1rem);
}

/* Using in calc() */
.grid {
  gap: calc(var(--spacing-base) * 1.5);
  padding: calc(var(--spacing-base) * 2);
}

💡 If --my-var is not defined, var(--my-var, fallback) uses the fallback. If it IS defined but invalid for the property, the browser uses initial or inheritnot the fallback.


Step 2: Scoping — Root vs Component


Step 3: Dynamic Theming via JavaScript


Step 4: @property — Registered Custom Properties

@property enables type-safe custom properties that can be animated:

💡 Without @property, CSS can't interpolate custom properties because it doesn't know their type. @property with syntax: '<color>' lets the browser do color interpolation between red and blue.


Step 5: Design Token Patterns


Step 6: CSS Variables in Media Queries & Containers


Step 7: Invalid Values and the Initial/Inherit Trick


Step 8: Capstone — CSS Variable Extractor + @property Generator

📸 Verified Output:


Summary

Feature
Syntax
Use Case

Declare variable

--name: value

Define token

Use variable

var(--name)

Apply token

With fallback

var(--name, fallback)

Safe usage

JS read

getComputedStyle(el).getPropertyValue('--name')

Read at runtime

JS write

el.style.setProperty('--name', value)

Dynamic theming

Register type

@property --name { syntax: '<color>' }

Animatable variables

Component scope

selector { --name: value }

Local override

Design tokens

Primitive → Semantic → Component

Token architecture

Last updated