a.k.a. CSS Variables
brand colors, sizes, fonts, etc…
button-background, primary-grid…
hsl(331deg 42% 30%)
color-mix(in oklab, darkRed 73.29%, mediumBlue)deep-raspberry’
best-color’
action’
link-text’ button-background’
--deep-raspberry: hsl(322, 92%, 24%);
--best-color: var(--deep-raspberry);
--action: var(--best-color);
--link-text: var(--action);
--button-background: var(--action);


(in the cascade)
--name: value;
--dashed-idents
For mixing custom & built-in identifiers
<dashed-ident>s are <custom-ident>s, but not vice versabuilt-in-property: value;
--custom-property: value;
-webkit-property -moz-property -ms-property
--property
-<empty>-property.warning {
--state-color: maroon;
}
.alert {
border: medium solid var(--state-color);
}
var( --property )
var function
button {
background-color: var(--button-background);
}

html { /* or :root */
--all-my: variables;
--defined: on the;
--root: element;
}
result: 0-1 cascaded values
result: one specified value
value from direct parent



demo:
[demo]:
background(including text colors)
(including anything box-related)
spans) If I added a
spanin the middle of this paragraph, what styles would I expect to apply automatically inside thespanso that the span doesn’t change anything?
— Internal Monologue
[demo]:
all:initial on the span/* 😭 Nooooooo */
html { box-sizing: border-box; }
* { box-sizing: inherit; }
/* 🥳 Much better */
* { box-sizing: border-box; }
Each property has an initial value, defined in the property’s definition table.
— Cascade & Inheritance, § 7.1. Initial Values
[Demo lookup]:
If the property is not an inherited property, and the cascade does not result in a value, then the specified value of the property is its initial value.
— Cascade & Inheritance, § 7.1. Initial Values
html {
font-size: var(--i-never-specified-a-value);
}
like Undefined in JS
var() become…
Invalid At Computed Value Time
_unset_--my-variable: initial;
color: var(--my-variable, CanvasText);
var(--my-color, teal)
/* fallback: 'Georgia, Palatino, serif' */
var(--my-font, Georgia, Palatino, serif)
var(--btn-color, var(--action, teal))
all shorthandall shorthand propertyinitialinheritunset (inherit or initial)revert (previous cascade origin)revert-layer (previous cascade layer)allinitial & inherit
choose your default, explicitly
unset
whichever default is appropriate
unset insteadinitial or inherited valuebody { margin: unset; }

initial value,display:inlinerevert
defer to previous origin
revertrevert-layer
defer to previous layer (or previous origin)
revert-layerunset or one of the revert valueshtml {
--color: teal;
--color: initial;
background: black;
background: var(--color, red);
}
0+ declared values)0|1 cascaded value)1 specified value)1 computed value)1 used value)1 actual value)p {
color: hotPink; /* rgb(255, 105, 180) */
border-color: currentColor; /* rgb(255, 105, 180) ? */
font-size: 1.2em; /* 19.2px ? */
/* these require formatting */
width: 80%; /* still 80% */
height: auto; /* still auto */
}
currentColor!)and this is not legal advice
currentColor
Inherits as Keyword
It should re-calculate when the color changes!
p {
--my-size: 1.5lh; /* 1.5em */
--my-color: hotPink; /* hotPink */
}
lh knowing what line to measurehtml {
--my-size: 1.5lh; /* 1.5lh */
--calc: calc(var(--my-size) * 2);
}
p {
/* --calc: calc(1.5lh * 2) */
/* not calc(var(--my-size) * 2) */
}
var()
p {
/* inherited calc(1.5lh * 2) */
color: var(--calc); /* unset */
min-height: var(--calc); /* 3lh */
}
demo:
![Image of animated Pinochio, no longer a puppet, saying I'm a real [property]](/img/OEeDJz1FtS-426.jpeg)
@property --brand-color {
syntax: "<color>";
inherits: true;
initial-value: hotPink;
}
syntax, inherits, and (usually) initial
inherits
true or false
/* replace 'initial' with any default value */
* { --this-property: initial; }
syntax…
Supported Names
Or "*" for ‘universal syntax’
(depending on syntax)
demo:
.yes-number-to-length {
--number: 1;
--length: calc( var(--number) * 1em);
/* not `var(--number)em` */
}
calc().no-length-to-number {
--length: 1em;
--number: calc( var(--length) / 1em );
}
initial-value…
Must be Absolute
(when the syntax is not *)
* ~= Browser Default
initial values equivalent to spec initialflex: 1 on a non-flex item)display:inline any time it’s not in flow)html {
color-scheme: dark light;
/* ~ used: dark; */
}
div {
width: 80%;
/* ~ used: 1049.6px; */
/* ~ actual: 1050px; */
}
:root { --btn-color: maroon; }
html/:root, then inherit):root { --btn-color: maroon; }
/* html { --btn-color: maroon; } */
html or :rootLike <svg> or <xml> or <html>
demo:
demo:
* { --btn-color: hotPink; }
button { --btn-color: maroon; }
button[type='submit'] {
--btn-type: seaGreen;
}
[aria-pressed=true] {
--btn-state: rebeccaPurple;
}
[data-grid] > * { --grid-area: main; }
button {
background: var(--btn-context, maroon);
}
main { --btn-context: mediumVioletRed; }
[type='submit'] { --btn-context: steelBlue; }
button:focus { --btn-context: seaGreen; }
<button style="--btn-color: red;">
You're not the boss of me
</button>
/* --btn-color is not being used */
button {
background: seaGreen;
color: white;
}
[attr] ➡ Presence (even if empty)[attr="..."] ➡ Exact match[attr*="..."] ➡ Any match[attr~="..."] ➡ Space-delimited (like classes)[attr|="..."] ➡ Hyphen-delimited[attr^="..."] ➡ Starts with…[attr$="..."] ➡ Ends with…[attr="..." i|s] ➡ Case sensitivity<!-- Element-attached/inline -->
<div style="--ease: var(--in-out-back);">
[style*='--ease'] {
--in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);
--out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--in-out-back: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
html {
@media (prefers-color-scheme: dark) {
--os-mode: -1;
}
@media (prefers-color-scheme: light) {
--os-mode: 1;
}
}
[data-colors='light'] {
--html-mode: 1;
}
[data-colors='dark'] {
--html-mode: -1;
}
[data-colors] {
--mode: var(
--html-mode, var(
--user-mode, var(
--os-mode, 1
)
)
);
}
--user-mode set via JS

<section
class="sprite-demo"
:style="{
'--src': show.sprite.src,
'--columns': show.sprite.columns,
'--rows': show.sprite.rows,
}">...</section>
<div
v-for="action in show.actions"
:key="action.name"
:data-action="action.name"
:style="{
'--row': action.row,
}"
/>
(as we’ve known them)