How It Works
The clamp model behind every fluid utility, the progress formula, why tan(atan2()) replaces length division, and a fully worked numeric example.
The model
Fluidity maps a measured axis (viewport width, container width, or any length) to a value within a min–max range using a progress curve. The core formula is:
progress = clamp(0, (axis - lower) / (upper - lower), 1)
value = min + (max - min) × ease(progress)
progress measures how far the axis has traveled from lower to upper (clamped between 0 and 1).
The ease function then transforms that progress (linear, exponential, or logarithmic), and scales a value from min to max.
Why tan(atan2())?
CSS calc() can’t divide a length by a length.
(axis - lower) / (upper - lower) would require dividing 56rem by 56rem to get a unitless number.
To work around this, fluidity computes the same result using pure CSS math:
progress = clamp(0, tan(atan2(axis - lower, upper - lower)), 1)
atan2() takes two lengths and returns an angle (radians).
tan() converts that angle to a ratio.
The result is the exact same progress value, computed without length-by-length division.
Worked example: f6y-p-2/8
Here’s a traced example through a real padding utility across three viewport widths.
Setup:
- Utility:
f6y-p-2/8(padding, min 0.5rem, max 2rem) - Defaults:
--f6y-lower: 40rem,--f6y-upper: 96rem,--f6y-base: 2,--f6y-axis: 100vw
Below the lower bound (viewport 30rem)
axis = 30rem
progress = clamp(0, tan(atan2(30 - 40, 96 - 40)), 1)
= clamp(0, tan(atan2(-10, 56)), 1)
= clamp(0, -10/56, 1) (tan(atan2(y, x)) simplifies to y/x)
= clamp(0, -0.179, 1)
= 0 (clamped)
padding = 0.5rem + (2rem - 0.5rem) × 0 = 0.5rem
The padding is exactly the min value.
At the midpoint (viewport 68rem)
axis = 68rem
progress = clamp(0, tan(atan2(68 - 40, 96 - 40)), 1)
= clamp(0, tan(atan2(28, 56)), 1)
= clamp(0, tan(0.4636), 1)
≈ clamp(0, 0.5, 1)
= 0.5
For linear (no curve prefix):
padding = 0.5rem + (2rem - 0.5rem) × 0.5
= 0.5rem + 0.75rem = 1.25rem
For exponential (f6y-exp-p-2/8, base 2):
ease(0.5) = (2^0.5 - 1) / (2 - 1) = (1.414 - 1) = 0.414
padding = 0.5rem + 1.5rem × 0.414 = 0.5rem + 0.621rem ≈ 1.121rem
For logarithmic (f6y-log-p-2/8, base 2):
ease(0.5) = log(1 + (2 - 1) × 0.5, 2) = log(1.5, 2) ≈ 0.585
padding = 0.5rem + 1.5rem × 0.585 = 0.5rem + 0.878rem ≈ 1.378rem
Beyond the upper bound (viewport 110rem)
axis = 110rem
progress = clamp(0, tan(atan2(110 - 40, 96 - 40)), 1)
= clamp(0, tan(atan2(70, 56)), 1)
= clamp(0, 70/56, 1) (tan(atan2(y, x)) simplifies to y/x)
= clamp(0, 1.25, 1)
= 1 (clamped)
padding = 0.5rem + 1.5rem × 1 = 2rem
The padding is exactly the max value.
Value forms
Every utility family (spacing, sizing, typography, etc.) accepts the same value modifier forms. The kind table in the assignment context defines what the bare default is for each property:
- Pair:
-2/8: both bounds from the theme/scale (for example,spacing(2)andspacing(8)) - Arbitrary:
-[1rem]/[3rem]: both bounds as bracketed literal CSS values - Mixed:
-2/[3rem]: one from the scale, one arbitrary - Theme (where applicable):
-sm/xl: theme keys (for example, breakpoint or container keys) - Min only:
-2: the max equalsmin × --f6y-ratio(default 2×) - Bare (no value):
f6y-p: min falls back to the property’s default, max derived asdefault × ratio
Within any form, all three curves are available: f6y-p-2/8, f6y-exp-p-2/8, f6y-log-p-2/8.