joel.design/system← Back to site
Foundations / Space

4 atomic, 8 semantic.

Every gap on joel.design is a multiple of 4. Most are multiples of 8. The exceptions exist because the page’s baseline grid demands them, not because I eyeballed it. The system is the rhythm.

Why 4 and 8
The de-facto modern web spacing system. 4px is the smallest unit the eye reliably sees as deliberate. 8px is the layout-grid step nearly every modern design system uses (Atlassian, Material, IBM Carbon, Tailwind defaults). Locking to it means components compose without measurement.

Scale.

Eleven steps from zero to 120px. The bar visualization is to scale. What you see is what gets rendered. Use semantic tokens (--space-N) in code, not raw pixels.

--space-0
No gap. Component-internal collapse.
0px
--space-1
Hairline gaps. Inline icon-text. Atomic baseline.
4px
--space-2
Tight stacks. Form field internals. Tag padding.
8px
--space-3
Inline groups. Button gap.
12px
--space-4
Card padding. Default body block spacing.
16px
--space-5
Section internal padding. Form group spacing.
24px
--space-6
Card-to-card gap. Major heading-to-body.
32px
--space-7
Section-to-section. Hero internals.
48px
--space-8
Section padding (vertical). Major page rhythm.
64px
--space-9
Top-of-page hero pad. Section-pad on desktop.
80px
--space-10
Page-foot pad. Generous landing breathing room.
120px

Baseline grid.

Type sits on an 8px baseline grid. Headings, body, captions, line-heights all snap to the same rhythm. Below: a real headline + body block with the grid overlay turned on so you can see the alignment.

Reduce the noise.

Brand strategy, web design, and automation from a one-person studio. I design it. I build it. It works. The grid behind this paragraph is doing the heavy lifting.

Section padding.

Sections use a single shared padding token: clamp(56px, 8vw, 80px) vertical, clamp(24px, 4vw, 72px) horizontal. The clamp lets the page breathe at desktop without crushing on mobile.

Rules.

  • Always a multiple of 4. If your gap isn’t in the scale, you’re inventing a new value. Don’t.
  • Prefer the larger step at higher scopes. Layout-level gaps (section-to-section) are 64–120. Component-level (card padding) are 16–32. Component-internal (icon-text gap) are 4–12.
  • Use clamp() for section padding so vertical rhythm scales between mobile and desktop without media queries.
  • Asymmetric padding is allowed for optical centering. When a font’s metrics put text high in its line-box (Calibre), use 1px more top than bottom. The system absorbs this. It’s still on the grid.