---
title: How It Works
description: The clamp model behind every fluid utility, the progress formula, why tan(atan2()) replaces length division, and a fully worked numeric example.
sidebar:
  order: 1
---

## 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:

```text
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:

```text
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)

```text
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)

```text
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):

```text
padding = 0.5rem + (2rem - 0.5rem) × 0.5
        = 0.5rem + 0.75rem = 1.25rem
```

For **exponential** (`f6y-exp-p-2/8`, base 2):

```text
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):

```text
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)

```text
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)` and `spacing(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 equals `min × --f6y-ratio` (default 2×)
- **Bare** (no value): `f6y-p`: min falls back to the property's default, max derived as `default × ratio`

Within any form, all three curves are available: `f6y-p-2/8`, `f6y-exp-p-2/8`, `f6y-log-p-2/8`.

**[Curves](/concepts/curves)**

Compare exponential and logarithmic ease functions in depth.

**[All Utilities](/utilities)**

Browse the 11 property families and their modifiers.
