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.

Open
Hover the card, or tab to its link. The arrow turns, the bar grows and the last line fades in, all together, and the readout runs through the numbers between 0 and 1 instead of jumping.
Code CSS · 27 lines
@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 3 reasons · 5 rules · support · credits

Why it works

  1. An unregistered custom property is a string, and a string cannot be interpolated. Registering it with a syntax gives it a type, and the browser then transitions it like any number.
  2. One transition with one easing drives every dependent value. The children derive theirs with calc(), so the parts stay in step.
  3. inherits: true passes the number down to the children that use it.

Rules

  1. initial-value is required for every syntax except "*".
  2. rotate, scale and translate do nothing on an inline element. Give the element display: inline-block or another box type first.
  3. A registration is global. Register each name once and keep the names specific.
  4. A script only writes the variable, as in el.style.setProperty("--x", "40%"). The easing and duration stay in CSS.
  5. 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