(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
span
in 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
initial
inherit
unset
(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 :root
Like <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)