Skip to content
milan.swiss Halbton v0.1.0
Concept project

Foundations

Spacing

Ten steps on a 4px base. The scale is linear at the bottom, where small differences are visible, and roughly geometric above — because past about 16px nobody can tell 20 from 24 without measuring.

The scale

4px base, doubling from 8. Every gap in the system is one of these.

The first four steps go up by 4px. After that they roughly double. That shape is deliberate: at small sizes a 4px difference is the difference between a label touching its input and not, so the scale needs resolution there. At large sizes the same 4px is invisible, and offering it only invites two engineers to pick differently for the same gap.

0 · 0 · 0px
1 · 0.25rem · 4px
2 · 0.5rem · 8px
3 · 0.75rem · 12px
4 · 1rem · 16px
5 · 1.5rem · 24px
6 · 2rem · 32px
7 · 3rem · 48px
8 · 4rem · 64px
9 · 6rem · 96px
What each step is actually for. Steps with no listed use are not needed yet.
Token rem px Use
--ht-space-0 0 0px Explicit zero, so a reset reads as a decision rather than an omission.
--ht-space-1 0.25rem 4px Icon to its label. Nothing else.
--ht-space-2 0.5rem 8px Inside a control — chip padding, badge gaps.
--ht-space-3 0.75rem 12px Between related controls; table cell padding.
--ht-space-4 1rem 16px The default gap. Panel padding, paragraph spacing.
--ht-space-5 1.5rem 24px Between a heading and its content.
--ht-space-6 2rem 32px Between subsections.
--ht-space-7 3rem 48px Above an h2 — the main rhythm of a docs page.
--ht-space-8 4rem 64px Between major page regions.
--ht-space-9 6rem 96px Page bottom padding, so the last line is not against the fold.

Vertical rhythm

Documentation pages use three gaps and no others: 7 above a section heading, 5 between a heading and its first content, 4 between paragraphs. That is the entire vertical system on this site.

the whole page rhythm
.page h2 { margin-top: var(--ht-space-7); }
.page h2 + * { margin-top: var(--ht-space-5); }
.page p + p { margin-top: var(--ht-space-4); }

/* Gaps live on the container, never as a margin on the child. */
.toolbar {
  display: flex;
  gap: var(--ht-space-3);
}

When not to use the scale

  • Optical alignment. Nudging an icon half a pixel to sit on a baseline is not spacing, it is drawing. Do it in the component and say so in a comment.
  • Borders and hairlines. A 1px rule is not space-0 rounded up.
  • Anything derived from content. A dropdown positioned under its trigger is computed, not spaced.