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.
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.
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.