Skip to content

Proportion system

Spacing

Eleven spacing steps taken from the Fibonacci sequence on a 16 px base, with the corner radii that go with them.

The sequence

Each Fibonacci number is the sum of the two before it:

F(n)=F(n−1)+F(n−2),F(1)=F(2)=1F(n) = F(n-1) + F(n-2), \qquad F(1) = F(2) = 1

Draw a square for each term and wind them around one another, and the corners of the squares trace a spiral. It is the same shape as a nautilus shell, a sunflower head or the arms of a galaxy: growth in which each step is a fixed proportion of the last.

5813213455
Each square is the sum of the two before it. The arc through every square is a golden spiral, the shape of a nautilus shell.

Why it works

The ratio of neighbouring terms settles on the golden ratio, so any two adjacent steps in the scale feel related:

φ=1+52≈1.618034,lim⁡n→∞F(n)F(n−1)=φ\varphi = \frac{1+\sqrt{5}}{2} \approx 1.618034, \qquad \lim_{n\to\infty}\frac{F(n)}{F(n-1)} = \varphi

The ratio is computed here. phi = 1.618034; the error column is F(n) / F(n-1) minus phi.
nF(n)F(n) / F(n-1)Error
211.000000-0.618034
322.000000+0.381966
431.500000-0.118034
551.666667+0.048633
681.600000-0.018034
7131.625000+0.006966
8211.615385-0.002649
9341.619048+0.001014
10551.617647-0.000387
11891.618182+0.000148
121441.617978-0.000056
132331.618056+0.000022

The first few steps are coarse (1, 2, 3, 5 differ by 100%, 50%, 67%) and by the tenth term the ratio is within a thousandth of phi. That matches how spacing is used: small steps are fine adjustments and large steps separate regions.

The scale

The base is 16 px, which is 1 rem on the web and 16 dp in Flutter. Every step is a whole number of pixels, and each token is a multiple of the 16 px unit, so the web and Flutter agree to the pixel. Tailwind reads the tokens as p-f13, gap-f8 and so on; the number is the pixel value.

TokenpxremStepTypical use
--spacing-f110.0625Hairline border
--spacing-f220.125Focus ring, divider weight
--spacing-f330.1875Optical nudge
--spacing-f550.3125Icon to label gap, chip padding
--spacing-f880.5Inline gap, small control padding
--spacing-f13130.8125Stack gap, compact card padding
--spacing-f21211.3125Card padding, group gap
--spacing-f34342.125Screen gutter, loose padding
--spacing-f55553.4375Section gap
--spacing-f89895.5625Hero gap
--spacing-f1441449Page-level gap

Corner radii

Radii use the same numbers. Anything fully rounded is a pill and uses the platform's full-round shape instead of a number.

f3Hairline marks, focus ring corners
f5Inline code, tags
f8Inputs, small controls
f13Tiles, small cards
f21Cards, panels
f34Sheets, dialogs
fullPills, chips, segmented controls

Rules

  1. Use only these steps for padding, margin, gap, offsets and radii. Never write a pixel value that is not on the scale.
  2. Neighbours inside, a step up outside. Space between related things is one step smaller than the space around the group. Padding inside a card is 21, the gap between cards is 21 or 34, and the gap between sections is 55.
  3. Skip a step to make a difference visible. If two gaps need to read as different, use steps that are two apart (8 and 21), not neighbours (13 and 21).
  4. Never subdivide a step. If a gap needs half of 13, the layout needs a different structure, not a new number.
  5. Do not carry meaning through space alone. Separation also needs a visible boundary, label or alignment, because spacing is lost when text is enlarged.

Usage

html
<!-- Tailwind: the number is the pixel value --><div class="grid gap-f21 p-f21 rounded-f21">  <p class="mb-f13">…</p></div>
css
/* the equivalent plain CSS */.card {  padding: var(--spacing-f21);  border-radius: var(--radius-f21);}
scale.css
@theme static {  --spacing-f1: calc(var(--u) * 0.0625);  --spacing-f2: calc(var(--u) * 0.125);  --spacing-f3: calc(var(--u) * 0.1875);  --spacing-f5: calc(var(--u) * 0.3125);  --spacing-f8: calc(var(--u) * 0.5);  --spacing-f13: calc(var(--u) * 0.8125);  --spacing-f21: calc(var(--u) * 1.3125);  --spacing-f34: calc(var(--u) * 2.125);  --spacing-f55: calc(var(--u) * 3.4375);  --spacing-f89: calc(var(--u) * 5.5625);  --spacing-f144: calc(var(--u) * 9);  --radius-f3: calc(var(--u) * 0.1875);  --radius-f5: calc(var(--u) * 0.3125);  --radius-f8: calc(var(--u) * 0.5);  --radius-f13: calc(var(--u) * 0.8125);  --radius-f21: calc(var(--u) * 1.3125);  --radius-f34: calc(var(--u) * 2.125);  --radius-full: calc(infinity * 1px);}