(especially Stacy & David)
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);

Until we apply them
button {
background-color: var(--button-background);
}



(in the cascade)
.warning {
--state-color: maroon;
}
--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.ಠ_ಠ {
--(╯°□°)╯: ︵┻━┻;
}
Unlike other CSS properties, custom property names are not ASCII case-insensitive.
<custom-ident>s(otherwise discarded at parse-time)
.ಠ_ಠ {
--(╯°□°)╯: ︵┻━┻;
}
.ಠ_ಠ {
--(╯°□°)╯: ︵┻━┻;
color: var(--(╯°□°)╯);
}
.ಠ_ಠ {
color: ︵┻━┻;
}
var() output…
Not Validated .ಠ_ಠ {
--(╯°□°)╯: ︵┻━┻;
color: var(--(╯°□°)╯);
}
button {
--fancy-color: oklch(0.8 0.1 0);
color: pink;
color: var(--fancy-color);
}
button {
--fancy-color: oklch(0.8 0.1 0);
/* color: pink; DISCARDED by cascade */
color: var(--fancy-color);
}
button {
--fancy-color: oklch(0.8 0.1 0);
/* color: pink; DISCARDED by cascade */
/* color: var(--fancy-color); INVALID */
}
var() become…
Invalid At Computed Value Time
@supports when setting variablesresult: 0-1 cascaded values
result: one specified value
value from direct parent



main { --action: maroon; }
aside { --action: teal; }
footer { --action: rebeccaPurple; }
button { background: var(--action); }
button { background: blue; }
main button { background: maroon; }
aside button { background: teal; }
main aside button { background: hotPink; }
anywhere in the DOM
from any ancestor
[demo]:
If I added a
spanin the middle of this paragraph, what styles would I expect to apply automatically inside thespan?
— Internal Monologue
(spans) (including anything box-related)
(including text colors)
Each property has an initial value, defined in the property’s definition table.
— Cascade & Inheritance, § 7.1. Initial Values
[Demo]:
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
available on every CSS property
initialinheritunset (inherit or initial)revert (previous cascade origin)revert-layer (previous cascade layer)initial & inherit
choose your default, explicitly
unset
whichever default is appropriate
body { margin: unset; }
revert & revert-layer
defer to previous origin or layer
unset or one of the revert valueshtml {
--color: teal;
--color: initial;
background: black;
background: var(--color, red);
}
html {
font-size: var(--i-never-specified-a-value);
}
like Undefined in JS
var() become…
Invalid At Computed Value Time
result: the property is un-set
var(--undefined, fallback)
var(--my-color, teal)
/* fallback: 'Georgia, Palatino, serif' */
var(--my-font, Georgia, Palatino, serif)
var(--btn-color, var(--action, teal))
html { --my-color: red; }
@supports (color: oklch(0% 0% 0)) {
html { --my-color: oklch(65% 0.2625 350.47); }
}
html {
--guaranteed-invalid: initial;
}
initial valuemaking relative values absolute
p {
color: currentColor; /* rgb(0, 0, 0) ? */
font-size: 1.2em; /* 19.2px ? */
border-color: hotPink; /* rgb(255, 105, 180) */
width: 80%; /* 80% (requires layout) */
height: auto; /* auto (requires layout) */
}
currentColor!)currentColor
Inherits as Keyword
It should re-calculate when the color changes!
p {
--my-size: 1.5lh; /* 1.5em */
--my-color: hotPink; /* hotPink */
}
var() Substitution
p {
--my-size: 1.5lh; /* 1.5em */
--alias: var(--my-size); /* 1.5em */
--calc: calc(var(--alias) * 2); /* calc(1.5lh * 2) */
}
var()
p {
--calc: calc(var(--alias) * 2); /* calc(1.5lh * 2) */
color: var(--calc); /* unset */
min-height: var(--calc); /* 3lh */
}
demo:
@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:
.number-to-length {
--number: 1;
--length: calc( var(--number) * 1em);
/* not `var(--number)em` */
}
calc().number-to-length {
--length: 1em;
--number: calc( var(--length) / 1em );
}
initial-value…
Must be Absolute
(when the syntax is not *)
* ~= Browser
initial values equivalent to spec initialflex: 1 on a non-flex item)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-color: seaGreen; }
[aria-pressed=true] { --btn-color: 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)