Smashing Workshop
controlling the matrix
workshops.oddbird.net/smashing24/variables/
(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>
<custom-ident>
built-in-property: value; --custom-property: value;
-
webkit
-property
moz
ms
--property
-<empty>-property
.alert { border: medium solid var(--state-color); }
var(
)
var
.ಠ_ಠ { --(╯°□°)╯: ︵┻━┻; }
Unlike other CSS properties, custom property names are not ASCII case-insensitive.
— CSS Custom Properties Level 1
(otherwise discarded at parse-time)
.ಠ_ಠ { --(╯°□°)╯: ︵┻━┻; color: var(--(╯°□°)╯); }
.ಠ_ಠ { 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 */ }
@supports
result: 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 the span?
span
— 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.
available on every CSS property
initial
inherit
unset
revert
revert-layer
choose your default, explicitly
whichever default is appropriate
body { margin: unset; }
defer to previous origin or layer
html { --color: teal; --color: initial; background: black; background: var(--color, red); }
html { font-size: var(--i-never-specified-a-value); }
like Undefined in JS
Undefined
result: the property is un-set
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; }
making 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
It should re-calculate when the color changes!
p { --my-size: 1.5lh; /* 1.5em */ --my-color: hotPink; /* hotPink */ }
p { --my-size: 1.5lh; /* 1.5em */ --alias: var(--my-size); /* 1.5em */ --calc: calc(var(--alias) * 2); /* calc(1.5lh * 2) */ }
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
syntax
inherits
true
false
/* replace 'initial' with any default value */ * { --this-property: initial; }
Or "*" for ‘universal syntax’
"*"
(depending on syntax)
.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
(when the syntax is not *)
*
flex: 1
html { color-scheme: dark light; /* ~ used: dark; */ }
div { width: 80%; /* ~ used: 1049.6px; */ /* ~ actual: 1050px; */ }
:root { --btn-color: maroon; }
html
:root
:root { --btn-color: maroon; } /* html { --btn-color: maroon; } */
Like <svg> or <xml> or <html>
<svg>
<xml>
<html>
* { --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]
[attr
=
"..."]
="..."]
~
|
^
$
[attr="..."
i
s
]
<!-- 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
<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)
Navigate slides using the arrow-keys.