demo · v140

Cross-Type Grid

Which combinations of types does calc() let you mix? Length over length yields a number. Number times length yields a length. Two angles divided produce a number; one angle plus one length is still an error. The full matrix in one table.

lengthanglepercentagetimenumber
length L + L → length L + A L + L% → length L + T L × N → length
length (÷) L / L → number (new) L / A L / L% → number L / T L / N → length
angle A + L A + A → angle A + % A + T A × N → angle
angle (÷) A / L A / A → number (new) A / % A / T A / N → angle
time T + L T + A T + % T + T → time T × N → time
time (÷) T / L T / A T / % T / T → number (new) T / N → time

The big shift in 140 is X / X → number: same-type division finally produces a unitless value that can flow into opacity, flex-grow, animation iteration counts, anything that wants a plain number.

/* All of these previously needed a tan(atan2(...)) hack. */
.bar           { width:    calc(100% * (var(--w) / 100px));          }
.spinner       { opacity:  calc(var(--angle) / 1turn);                }
.delay-as-frac { z-index:  calc(var(--delay) / 1s * 60);              }

why N matters

A unitless number can be used as: a multiplier for any unit, an iteration count, an opacity, a flex factor, a Z-index, a grid track count. Once the engine can produce a number from typed inputs, every property that takes a number becomes addressable from a single typed custom property. That's what unlocks scroll-driven animation, container-query-driven typography, and the rest of the calc() story.

see also

scenario focus

Select a scenario to focus its rendered example and summary.