html:root--brand--gap1:root {2 --brand: tomato;3 --gap: 8px;4}5.card { --brand: teal; }6button {7 background: var(--brand);8 padding: var(--gap);9 color: var(--ink, white);10}body--brand--gapBuy--brand--gapdiv.card--brand--gapSave--brand--gaptomato8pxtomato 8pxtomato 8pxtomato 8pxtomato 8pxvar(--brand)var(--brand)tealtealwhitewhite16px16px16px16px16px
Left: style.css, the stylesheet with the custom propertiesRight: the element tree, with the values each element holdsTokens: values flowing down the tree and var() reading themLeft: the stylesheet, with two custom properties on :root, an override on .card and a button rule that reads them with var(). Right: the element tree. Each element shows the --brand and --gap values it holds; each button shows how it is drawn. Values flow down the tree (inheritance); var() reads the value each button holds, so one rule paints Buy tomato and Save teal; changing --gap once resizes both buttons. A real browser reads the whole stylesheet at once and works out every element's style in one pass. The figure adds the rules and declarations one at a time so you can see what each one does.

Declare and inherit

  1. A custom property is a property whose name starts with two dashes, like --brand. This :root rule stores two design choices: the colour tomato and an 8px gap. On its own it styles nothing; it just holds a value.

Read with var()

Tokens at scale

What happens

;; step 1/8 · declare
style.css, lines 1 to 4
  :root {
    --brand: tomato;
    --gap: 8px;
  }
--brand   a custom property, value tomato
--gap     a custom property, value 8px
names start with --, and are case-sensitive:
  --brand and --Brand are two different properties

A real browser reads the whole stylesheet at once and works out every element's style in one pass. The figure adds the rules and declarations one at a time so you can see what each one does. Before the button rule applies, a button keeps the browser's own default look (a light grey face and dark text). The padding drawn on each button is to scale with the --gap value, not with real screen pixels.