Skip to content
Retr0 Academy
Advanced CSS

Advanced CSS · 2 min read

Custom Properties and Theming

CSS variables, inheritance and the cascade, design tokens, dark mode, and changing variables from JavaScript.

Custom properties (CSS variables) are properties you invent, prefixed with --. Unlike preprocessor variables, they are live: they inherit through the DOM, react to media queries and can be changed at runtime by JavaScript. This site's whole retro theme is a set of them.

css

:root {
  --color-bg: #fff7e6;
  --color-ink: #1a1530;
  --color-accent: #ff3fa4;
  --space: 8px;
}
.button {
  background: var(--color-accent);
  padding: calc(var(--space) * 1.5) calc(var(--space) * 3);
}

Fallbacks and scope

css

color: var(--brand, hotpink);   /* fallback if --brand is not defined */
.card { --pad: 24px; }          /* scoped: only .card and its children see this value */
.card.compact { --pad: 12px; }  /* override per variant */

Design tokens: two layers

  1. Primitive tokens describe raw values: --pink-500: #ff3fa4.
  2. Semantic tokens describe purpose: --accent: var(--pink-500).

Components only use semantic tokens. A theme is then just a different mapping.

Light, dark and system theme with tokens
<div class="controls">
<button data-theme="light">Light</button>
<button data-theme="dark">Dark</button>
<button data-theme="system">System</button>
<label>Accent hue <input id="hue" type="range" min="0" max="360" value="328"></label>
</div>
<article class="card">
<h2>NEAR Smart Contracts</h2>
<p>6 lessons · Rust · Intermediate</p>
<button class="primary">Start course</button>
</article>

Edit this example in the Playground.

Open in Playground

Moving the slider changes one variable; every component that uses --accent updates instantly.

Reading and writing from JavaScript

js

const root = document.documentElement;
getComputedStyle(root).getPropertyValue("--hue"); // " 328"
root.style.setProperty("--hue", "190");

Summary

Define primitive and semantic tokens on :root, override them per theme or per component, honour prefers-color-scheme, and update variables from JavaScript for live theming.