· Working ·
4px and 8px grids: why an on-grid layout can still look off
A 4px or 8px grid makes every gap a multiple of one unit, but it doesn't create rhythm. This post covers why the 8px/4px grid is so common, then fixes an on-grid layout that still feels messy using three tiers of whitespace, with before-and-after CSS.
A 4px grid means every gap is a multiple of 4: 4, 8, 12, 16, 24. An 8px grid uses a bigger step. Both remove stray values like 13px, but neither creates rhythm. A layout reads well when whitespace has at least three distinct tiers: within a group, between groups, and between sections.
I'm Hai Le, a product designer who builds design systems and codes this site myself. The examples below use the site's real spacing scale.
Why is the 8px/4px grid so common?
The source most people point to is Google's Material Design. The Metrics & keylines page of the original Material guidelines, still online at m1.material.io, says: "All components align to an 8dp square baseline grid for mobile, tablet, and desktop." The same page aligns toolbar icons and type to a 4dp grid. So 8 is the step for layout and components, and 4 is the step for detail.
The practical reason is multiplication. Screens have different pixel densities, and the OS scales your design by 1.5, 2 or 3. An 8-unit gap at 1.5x is a clean 12 pixels. A 5-unit gap at 1.5x is 7.5, which the browser has to round, so two edges that should match can end up a pixel apart. Multiples of 4 stay whole at all of those factors.
The second reason is decision speed. With roughly ten allowed values, designers and developers stop debating 14 versus 15. Tailwind is built on the same unit: in Tailwind v4 the --spacing variable defaults to 0.25rem, or 4px, so gap-2 is 8px and p-6 is 24px.
Should you use a 4px or an 8px grid?
I use 4px as the base and 8px as the main step. Here is this site's spacing scale, taken from its DESIGN.md:
| Token | Value | Example use |
|---|---|---|
xxs | 2px | Hairline gaps, rarely used |
xs | 4px | Icon next to a label |
sm | 8px | Heading to the lead right below it |
md | 12px | Horizontal padding on a small button |
lg | 16px | Gap between cards in a 3-up row |
xl | 20px | Card interior padding |
2xl | 24px | Page gutter on mobile |
3xl | 32px | Column gap, page gutter on desktop |
4xl | 48px | Section padding on mobile |
5xl | 64px | Row gap in a feature grid |
6xl | 80px | Section padding from md up |
The scale includes 12 and 20, which don't divide by 8. They exist because some spots are too tight at 8 and too loose at 16, card padding being the obvious one. Adding the 20px step meant renaming every token from xl up, and the migration mapping is written into the file so nobody uses an old name by mistake.
Why does an on-grid layout still look off?
The grid only guarantees that numbers divide by 4. It has no idea which gaps mean "same group" and which mean "boundary".
The mistake I see most: the gap between a heading and its lead equals the gap between two content blocks. Both are 24px, both are on-grid. People group things that sit close together, so when every gap is equal, the reader can't see where one group ends. The heading looks like it floats between two blocks.
How do you fix an on-grid layout that feels messy?
Here is a common section: heading, lead paragraph, then a row of cards. Every value divides by 4.
/* Before: on-grid, no hierarchy */
.section { padding-block: 24px; }
.section h2 { margin-bottom: 24px; }
.section .lead { margin-bottom: 24px; }
.cards { display: grid; gap: 24px; }
.card { padding: 24px; }
.card h3 { margin-bottom: 24px; }Six places share one value. A card's title sits as far from its description as one card sits from the next, and the section is only 24px away from whatever follows.
The fix splits whitespace into three tiers, named by role:
/* After: three tiers, each at least double the one below */
:root {
--space-group: 8px; /* within a group */
--space-block: 32px; /* between groups */
--space-section: 80px; /* between sections */
}
.section { padding-block: var(--space-section); }
.section h2 { margin-bottom: var(--space-group); }
.section .lead { margin-bottom: var(--space-block); }
.cards { display: grid; gap: 16px; }
.card { padding: 20px; }
.card h3 { margin-bottom: var(--space-group); }
@media (max-width: 767px) {
:root { --space-section: 48px; }
}Three changes do the work. The heading hugs its lead at 8px, so the two read as one unit. The lead sits 32px above the cards, four times that, so the jump to a new group is obvious. Sections are 80px apart on desktop and 48px on mobile, the same two values this site uses for every section.
My own rule: each tier is at least double the one below it. A smaller jump, like 16 to 24, usually isn't enough for the eye to see a new group. Notice that the card padding (20px) and card gap (16px) don't follow the three tiers. They belong to the component, and they stay fixed wherever the card appears.
In Tailwind, the "after" version comes down to a few classes:
<section class="py-12 md:py-20">
<h2 class="mb-2">…</h2>
<p class="mb-8">…</p>
<div class="grid gap-4 md:grid-cols-3">…</div>
</section>How do you put a spacing scale into a design system?
A spacing scale is a set of tokens, like colour and type. If the idea is new to you, read What is a design token first, then the naming questions in Design token FAQ.
In Figma, create a Number collection for spacing and bind it to auto layout gap and padding. Once the scale is a set of variables, nobody can type 13 by hand. The harder part is writing down what each step is for. "16px is the gap between cards in a 3-up row" helps a teammate, or an AI, pick the right value on a screen you never designed. I keep those rules in DESIGN.md, and What is DESIGN.md shows how.
Whitespace and type go together. Vietnamese headings need line height for stacked diacritics, which I cover in Choosing a UI font for Vietnamese.
At Joyme I built the design system for the product's first version in three months, which you can see in the Joyme case study. If your team needs someone to set up a token scale and keep it in sync between Figma and code, you can read more about me.
Sources
- Material Design (v1): Metrics & keylines: 8dp baseline grid for components, 4dp for toolbar icons and type. Accessed 2026-10-04.
- Tailwind CSS v4.3,
theme.cssin thetailwindcsspackage:--spacing: 0.25rem. DESIGN.md(Layout section) in this site's repo.
Frequently asked questions
- Should I use a 4px or an 8px grid?
- Use 4px as the base unit and 8px as the main step. Most spacing should land on multiples of 8. Keep the 4px, 12px and 20px steps for small details inside components, like the gap between an icon and its label or button padding.
- Does Tailwind use a 4px grid?
- Yes. In Tailwind v4 the --spacing variable defaults to 0.25rem, which is 4px at a 16px root font size. So p-1 is 4px, p-2 is 8px and p-5 is 20px.
- Does line height need to be divisible by 4?
- Material Design says type aligns to a 4dp baseline grid. On the web I aim for large text styles to land near a multiple of 4, but I don't bend body line height just to divide evenly. On this site, 16px body text has a 22.4px line height.
- Do I still need a grid if I use Figma auto layout?
- Auto layout replaces dragging things onto a grid, but you still choose every gap and padding value. A 4px grid gives you the list of allowed values. Save them as Figma variables so nobody types 13 or 22 by hand.
You might also like
What is Claude Code? Install it and run your first session, no coding needed
A designer's walkthrough for people who have never opened a terminal: what Claude Code is, what you need, installing on macOS and Windows, a safe first session, and fixes for the usual errors. Every command comes from Anthropic's docs.
Working· 2026-10-04
Claude Code for designers: turning a Figma design into a working page
How I use Claude Code as a designer to get from Figma frames to a real, maintained website: what to set up, how to write rules the agent follows, a six-step workflow, and the mistakes I made building this site.
Working· 2026-10-04
What is Claude? A guide for people who have never used AI
Claude is Anthropic's AI assistant. This guide covers what it can do, how the free and paid plans differ, how to run your first conversation, and where Claude tends to get things wrong. Every feature and price was checked against Anthropic's own pages.
Working· 2026-10-04