demo · v138
Stagger orchestra
Four staggered animations on one page — pin-fall, rainbow chord, radial fan, numbered card grid — all driven by sibling-index() and sibling-count(). Add or remove items with the buttons and the entire choreography re-balances itself, without ever recomputing anything in JS.
Behind a flag in earlier builds.
sibling-index() and sibling-count() ship unflagged in Chrome 138. If your browser doesn't support them the demo renders unstaggered and the colour hue collapses to one tone.
probing sibling-index()…
1 — Pin-fall · per-pin delay = sibling-index() × 60ms, duration tied to sibling-count()
2 — Rainbow chord · hue = (sibling-index() / sibling-count()) × 360deg, height linear with index
3 — Radial fan · rotation = ((i - 1) / (n - 1) − 0.5) × 120deg, dealt one card at a time
4 — Numbered grid · counter + sibling-count() shows live "n of N" without any JS
The pattern
li {
--i: sibling-index();
--n: sibling-count();
animation-delay: calc(var(--i) * 60ms); /* stagger */
--hue: calc((var(--i) - 1) / var(--n) * 360deg); /* per-child colour */
--angle: calc(((var(--i) - 1) / (var(--n) - 1) - 0.5)
* 120deg); /* radial layout */
}
What's happening
sibling-index()returns the element's 1-based position among its element siblings.sibling-count()returns the total.- Both are live — adding or removing siblings invalidates the layout and the animation choreography re-runs.
- Used inside
calc(), they replace the entire family of "per-child" things that used to need JS or:nth-child(N) { … }exhaustive lists. - The radial fan would have been impossible to make responsive — you'd hardcode each angle for each n. Now adding the 9th card auto-rebalances the other 8.
- The "1 of 12" label is a CSS counter (
counter-increment: cardno) plussibling-count()exposed via a data attribute that JS sets once.