Entry 03
Transition a custom property with @property
Use it when one state change should drive several values together, or when a script feeds a number such as pointer position or progress into CSS and the result should ease.
Code
@property --progress {
syntax: "<number>";
inherits: true;
initial-value: 0;
}
.card:focus-within { --progress: 1; }
@media (hover: hover) and (pointer: fine) {
.card:hover { --progress: 1; }
}
.card .icon {
display: inline-block;
rotate: calc(var(--progress) * 90deg);
}
.card .bar {
transform-origin: left;
scale: calc(0.25 + var(--progress) * 0.75) 1;
}
.card .more { opacity: var(--progress); }
@media (prefers-reduced-motion: no-preference) {
.card { transition: --progress 0.3s var(--ease-out, ease-out); }
}Why it works, the rules and the credits
Why it works
- An unregistered custom property is a string, and a string cannot be interpolated. Registering it with a
syntaxgives it a type, and the browser then transitions it like any number. - One transition with one easing drives every dependent value. The children derive theirs with
calc(), so the parts stay in step. inherits: truepasses the number down to the children that use it.
Rules
initial-valueis required for every syntax except"*".rotate,scaleandtranslatedo nothing on an inline element. Give the elementdisplay: inline-blockor another box type first.- A registration is global. Register each name once and keep the names specific.
- A script only writes the variable, as in
el.style.setProperty("--x", "40%"). The easing and duration stay in CSS. - Other useful types are
<length-percentage>for a gradient position and<angle>for a conic gradient.
Support
- Chrome
- 85
- Firefox
- 128
- Safari
- 16.4
Credits
Borrowed from: Stripe, on the stripe.com home page and its sales contact page
Docs: MDN: @property