demo · v138
Scroll direction indicator
A signed value --delta drives everything in this stage with no JS branching. sign() rotates an arrow, picks a hue, and switches a label. abs() sets bar width, distance, and intensity. One slider, two reactive panels, twelve coordinated computed values.
Unflagged in Chrome 138.
abs() and sign() are part of the CSS Values 4 math functions. Combined with typed arithmetic, also new in v138, they let you do branching that would have required JS or a polyfilled tan(atan2(…)) trick.
probing abs() / sign()…
Δ change · panel A
+0
color: oklch(from black ... calc(120deg - sign(Δ) * 120deg)) width: calc(abs(Δ) * 1%)
position from origin · panel B
distance 0
direction ·
distance = abs(pos) direction = sign(pos) // -1 / 0 / +1
The math
.meter {
--delta: 12;
--abs: abs(var(--delta)); /* 12 */
--sgn: sign(var(--delta)); /* +1 (or -1 if delta<0, or 0) */
/* sign picks the colour band: +1 → green, 0 → black, -1 → red */
color: oklch(from black calc(50% + abs(var(--delta))/100 * 25%) 0.2
calc(120deg - sign(var(--delta)) * 120deg));
/* arrow rotates 0deg (up) when sgn=+1, 360deg (still up) when 0, 180deg when -1 */
transform: rotate(calc(sign(var(--delta)) * 180deg + 180deg));
}
What's happening
abs(x)returns|x|at the same type asx. Soabs(-12px)is12px— not just a number.sign(x)returns-1,0, or+1. Plug it intocalc()to multiply something by direction.- Combined, they replace JS branches like
delta < 0 ? 'red' : 'green': it's justoklch(... calc(120deg - sign(delta)*120deg)). - Previously this required
:has(.negative)selectors, multiple style classes, or a custom property polyfill. With v138 it's one calc. - Combined with typed arithmetic (also new in v138), the same value can drive width, hue, rotation, and translate at once — see the panels above.