~/TechPurAI
~/tutorials/css-from-scratch/colors-units-and-css-custom-properties
beginner·part 5 of 22·4 min read

Colors, units, and CSS custom properties: building real design tokens

Updated Aug 16, 2026CSS

Every CSS value so far has used raw pixel numbers and hex colors written directly into each rule. This part covers the real unit types worth knowing, and the CSS feature that turns repeated raw values into a single, real, maintainable source of truth.

Real length units, and when each one actually matters

css
h1 { font-size: 40px; }     /* absolute — never scales */
h1 { font-size: 2.5rem; }   /* relative to the root font-size */
h1 { font-size: 2.5em; }    /* relative to the PARENT's font-size */
.hero { width: 100%; }      /* relative to the parent's width */
.hero { height: 100vh; }    /* relative to the viewport height */

px is an absolute unit — a real, fixed size regardless of any other setting. rem is relative to the root (<html>) element's font-size, which makes it the real, practical default for most sizing: if a visitor's browser is set to a larger default font-size for accessibility, every rem-based measurement scales proportionally, while px-based measurements stay rigid and ignore that real preference entirely. em is relative to the parent element's font-size specifically, which can compound unpredictably through nested elements — genuinely useful in a few specific cases, but rem is the safer real default for most sizing decisions.

Real color formats, and picking one deliberately

css
.price {
  color: #ff8a3d;                    /* hex */
  color: rgb(255, 138, 61);          /* rgb */
  color: rgb(255 138 61 / 0.8);      /* rgb with real alpha transparency */
  color: hsl(24, 100%, 62%);         /* hue, saturation, lightness */
}

All four represent the same real color. Hex is the most common in practice; rgb() with a slash and alpha value is the real, modern way to add transparency without a separate rgba() function; hsl() is genuinely useful specifically because its three values map to how people actually think about adjusting a color — increasing lightness or saturation directly, rather than recalculating three separate red/green/blue numbers by hand.

CSS custom properties: real, reusable design tokens

css
:root {
  --color-bg: #faf7f2;
  --color-ink: #2b2b2b;
  --color-accent: #ff8a3d;
  --color-line: #ddd;

  --space-sm: 0.5rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;

  --font-body: "Inter", sans-serif;
  --font-display: "Georgia", serif;
}
css
.product-card {
  background: var(--color-bg);
  border: 1px solid var(--color-line);
  padding: var(--space-lg);
  font-family: var(--font-body);
}

.price {
  color: var(--color-accent);
}

Custom properties (declared with a real -- prefix, read with var()) are genuine variables — a real, single source of truth for a value used repeatedly throughout Bright Leaf Coffee's stylesheet. Declaring them once on :root (the <html> element) makes them available everywhere else in the stylesheet, since custom properties are inherited the same way color and font-family are, covered in part 3.

Why it matters

Without custom properties, a real accent color used in twelve different places across a stylesheet means twelve separate edits the day that color needs to change — a genuine, real maintenance cost, and an easy place for one instance to be missed, leaving an inconsistent color slipped through unnoticed. One --color-accent declaration means one real edit updates every use at once.

A real, practical token set for this series' project

css
:root {
  --color-bg: #faf7f2;
  --color-panel: #ffffff;
  --color-ink: #2b2b2b;
  --color-muted: #6b6b6b;
  --color-accent: #ff8a3d;
  --color-line: #e5e0d8;

  --space-xs: 0.25rem;
  --space-sm: 0.5rem;
  --space-md: 1rem;
  --space-lg: 1.5rem;
  --space-xl: 2.5rem;

  --radius: 8px;
}

This is the real, complete token set every later part in this series builds on — every color, spacing value, and radius used from part 6 onward references one of these variables rather than a raw, repeated value, exactly the discipline that keeps a real stylesheet consistent as it grows across many more rules.

Custom properties can change per real context, unlike Sass variables

css
.card--featured {
  --color-accent: #4fd1c5;
}

Unlike a build-time preprocessor variable, a real CSS custom property can be redeclared within a more specific selector's scope, overriding its value for everything nested inside that selector only — here, a featured product card genuinely gets its own accent color, with zero change needed to any other rule that already references var(--color-accent). This dynamic, cascading behavior is a real, meaningful capability plain preprocessor variables never had.

Next: typography — real font-family stacks, @font-face, and building a genuine, consistent type scale.

VK

Vijay Kumar

Founder of TechPurAI — writing hands-on tutorials and honest tool breakdowns.

LinkedIn ↗
← previous4. The box model: content, padding, border, and marginnext →6. Typography: real font stacks, @font-face, and a consistent type scale