Layout & Spacing
Spacing and layout are what separate amateur designs from professional ones. Two designs can use the same fonts, colors, and components, and the one with better spacing will look dramatically better. Spacing creates visual relationships, establishes hierarchy, and makes content scannable.
The 8-Point Grid System
All spacing and sizing should be multiples of 8px. This is the most widely used grid system in modern UI design.
4px ████ (half-step for micro adjustments)
8px ████████ (smallest usable spacing)
12px ████████████ (tight spacing, icon padding)
16px ████████████████ (standard element spacing)
24px ████████████████████████ (medium spacing)
32px ████████████████████████████████ (between groups)
40px ████████████████████████████████████████ (between sections)
48px ████████████████████████████████████████████████ (section padding)
64px [larger bar] (major sections)
96px [larger bar] (page sections)
Why 8?
- Divisible by 2 and 4, so half and quarter steps are whole numbers
- Works cleanly on all screen densities (1×, 1.5×, 2×, 3×)
- Aligns with common device dimensions
- Wide enough that the eye can distinguish between steps (4px is hard to distinguish from 8px; 8px from 16px is clear)
When to use 4px: Icons, small badges, fine adjustments within components. Everything else should be 8px multiples.
Spacing Tokens
Don't use arbitrary pixel values. Define a spacing scale and use it everywhere:
:root {
--space-1: 4px; /* 0.25rem — Micro: icon internal padding */
--space-2: 8px; /* 0.5rem — XS: tight gaps, inline spacing */
--space-3: 12px; /* 0.75rem — SM: input padding, icon+label gap */
--space-4: 16px; /* 1rem — MD: default element spacing */
--space-5: 20px; /* 1.25rem — Between form fields */
--space-6: 24px; /* 1.5rem — LG: between card content areas */
--space-8: 32px; /* 2rem — XL: between groups/sections */
--space-10: 40px; /* 2.5rem — Between major groups */
--space-12: 48px; /* 3rem — Section padding (mobile) */
--space-16: 64px; /* 4rem — Section padding (desktop) */
--space-20: 80px; /* 5rem — Large section gaps */
--space-24: 96px; /* 6rem — Major page sections */
}
Applying Spacing Tokens
| Where | Token | Size | Example |
|---|---|---|---|
| Icon to label gap | space-2 | 8px | [icon] 8px [Label Text] |
| Input internal padding | space-3 | 12px | Padding inside an input field |
| Between form fields | space-5 | 20px | Gap between "Name" and "Email" fields |
| Between card content sections | space-6 | 24px | Gap between card title area and card body |
| Between content groups | space-8 | 32px | Gap between "Personal Info" and "Address" groups |
| Section padding (mobile) | space-12 | 48px | Vertical padding of a page section |
| Section padding (desktop) | space-16-24 | 64-96px | Vertical padding scales up on large screens |
Rule of thumb: spacing within groups < spacing between groups. If elements inside a card have 16px gaps, the gap between cards should be at least 24px.
Whitespace
Why Whitespace Matters
| More Whitespace | Less Whitespace |
|---|---|
| Premium, luxury feel | Dense, information-heavy feel |
| Easier to scan | More content per screen |
| Draws attention to content | Can overwhelm and cause decision fatigue |
| Apple, Stripe, Linear | Bloomberg Terminal, spreadsheets |
Neither is inherently better. Match the whitespace level to the product's purpose.
Whitespace Guidelines
- Group related elements with proximity. Items that belong together should be close. Items that don't should have more space between them.
BAD (equal spacing everywhere):
Full Name ← 24px
[___________] ← 24px
Email ← 24px
[___________] ← 24px
Street Address ← 24px
[___________] ← 24px
City ← 24px
[___________]
GOOD (proximity creates groups):
Full Name ← 8px
[___________] ← 16px
Email ← 8px
[___________]
← 32px (gap = new group)
Street Address ← 8px
[___________] ← 16px
City ← 8px
[___________]
Increase whitespace at larger screen sizes. A 48px section gap on mobile should become 80-120px on desktop. Don't just make the content wider.
Active whitespace around CTAs. Surround your primary action button with generous space so it stands out.
Consistent internal vs. external spacing on components. A card should have consistent padding internally (e.g., 24px on all sides) and consistent margins externally (e.g., 16px between cards).
When in doubt, add more space. Beginners use too little whitespace. Give content room to breathe.
Layout Patterns
The Container
Every page needs a centered, max-width container to prevent content from stretching across ultra-wide monitors:
.container {
width: 100%;
max-width: 1200px; /* Common: 1140px, 1200px, 1280px */
margin-left: auto;
margin-right: auto;
padding-left: 16px; /* Mobile gutters */
padding-right: 16px;
}
@media (min-width: 768px) {
.container {
padding-left: 24px;
padding-right: 24px;
}
}
@media (min-width: 1024px) {
.container {
padding-left: 32px; /* Desktop gutters */
padding-right: 32px;
}
}
| Container Width | Best For |
|---|---|
| 720px | Blog/article content (narrow, focused reading) |
| 960px | Simple marketing pages, single-column layouts |
| 1140px | Standard web apps, Bootstrap default |
| 1200px | Common modern default |
| 1280px | Data-heavy apps, dashboards |
| 1440px | Wide layouts, full-width apps |
| 100% (no max) | Full-bleed designs, dashboards, apps |
Card Grids
Cards are the most common content container. Use CSS Grid for responsive card layouts:
/* Auto-responsive cards — no breakpoints needed */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 24px;
}
This creates cards that are at least 300px wide and fill available space. The grid automatically adjusts the number of columns based on viewport width.
| Min Card Width | Result at 1200px | Best For |
|---|---|---|
| 200px | 5 columns | Small cards, thumbnails |
| 280px | 4 columns | Product cards, previews |
| 300px | 3 columns | Standard content cards |
| 380px | 3 columns (wider) | Feature cards, blog posts |
| 500px | 2 columns | Detailed cards, case studies |
Split/Two-Column Layout
.split {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 48px;
align-items: center;
}
@media (max-width: 768px) {
.split {
grid-template-columns: 1fr; /* Stack on mobile */
gap: 24px;
}
}
Sidebar Layout
.sidebar-layout {
display: grid;
grid-template-columns: 260px 1fr; /* Fixed sidebar */
gap: 32px;
}
@media (max-width: 768px) {
.sidebar-layout {
grid-template-columns: 1fr; /* Stack on mobile */
}
}
Common sidebar widths:
| Width | Use Case |
|---|---|
| 200-240px | Narrow sidebar, icon + short labels |
| 260-280px | Standard sidebar, comfortable text labels |
| 300-320px | Wide sidebar, sidebar with nested items |
| 360-400px | Very wide, settings panel or secondary content |
Holy Grail Layout
Header plus sidebar plus main plus footer, the classic app layout:
.app-layout {
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: 260px 1fr;
min-height: 100vh;
}
.header { grid-column: 1 / -1; } /* Full width */
.sidebar { grid-row: 2; }
.main { grid-row: 2; overflow-y: auto; }
.footer { grid-column: 1 / -1; } /* Full width */
Stack Layout
The simplest pattern: vertically stacked elements with consistent spacing:
.stack > * + * {
margin-top: 16px; /* Consistent gap between all children */
}
/* Or with gap (no margin collapsing issues) */
.stack {
display: flex;
flex-direction: column;
gap: 16px;
}
Responsive Spacing
Spacing should scale with screen size. Mobile screens need tighter spacing to fit content; desktop screens need looser spacing to avoid vast empty areas.
Approach 1: Breakpoint-Based Tokens
:root {
--section-padding: 48px;
--card-gap: 16px;
--container-gutter: 16px;
}
@media (min-width: 768px) {
:root {
--section-padding: 80px;
--card-gap: 24px;
--container-gutter: 24px;
}
}
@media (min-width: 1200px) {
:root {
--section-padding: 120px;
--card-gap: 32px;
--container-gutter: 32px;
}
}
Approach 2: Fluid Spacing with clamp()
:root {
--section-padding: clamp(48px, 8vw, 120px);
--card-gap: clamp(16px, 2vw, 32px);
--container-gutter: clamp(16px, 3vw, 48px);
}
Responsive Spacing Scale
| Token | Mobile (< 768px) | Tablet (768-1023px) | Desktop (1024px+) |
|---|---|---|---|
| Element gap | 8-16px | 16px | 16px |
| Group gap | 16-24px | 24-32px | 32px |
| Section padding | 32-48px | 64-80px | 80-120px |
| Page margins | 16px | 24px | 32-48px |
The Spacing Relationship Hierarchy
Space communicates relationships. Use this hierarchy consistently:
TIGHTEST SPACING → LOOSEST SPACING
Within a component → Between components → Between groups → Between sections
(8-16px) (16-24px) (24-48px) (48-120px)
Example:
┌─────────────────────────────────┐
│ Card Title ← 8px │ ← Within component
│ Card subtitle ← 16px │
│ Card body text... ← 24px │
│ [Action Button] │
└─────────────────────────────────┘
← 24px ← Between components
┌─────────────────────────────────┐
│ Another Card... │
└─────────────────────────────────┘
← 48px ← Between groups
┌─────────────────────────────────┐
│ DIFFERENT SECTION │
Padding vs. Margin
| Property | Use For | Behavior |
|---|---|---|
| Padding | Space inside an element | Increases the element's clickable/visible area |
| Margin | Space between elements | Creates separation from siblings |
| Gap | Space between grid/flex children | Clean, no collapsing issues, preferred |
Prefer gap over margin when using flexbox or grid. It's cleaner, more predictable, and doesn't have margin collapsing issues.
/* Prefer this */
.card-grid {
display: grid;
gap: 24px; /* Clean, consistent, no collapsing */
}
/* Over this */
.card {
margin-bottom: 24px;
margin-right: 24px;
/* Last items have unwanted margin, needs negative margin hacks */
}
Common Layout Mistakes
| Mistake | Why It Looks Bad | Fix |
|---|---|---|
| Content stretching to full viewport width on large screens | Lines become too long (80+ characters), content is hard to scan | Use a max-width container (1200-1440px) |
| Equal spacing everywhere | No visual grouping, everything blurs together | Use less space within groups, more between groups |
| Inconsistent padding in cards | Some cards have 12px, others 24px, looks unfinished | Define a component padding token and use it consistently |
| No responsive spacing | Desktop-sized margins crush mobile content | Scale spacing down on mobile, up on desktop |
| Using pixel values directly | Hard to maintain, inconsistent across the codebase | Use spacing tokens (CSS variables) |
| Fixed heights on containers | Content overflows or creates unwanted scroll | Use min-height or let content determine height |
| Vertical rhythm breaks | Line heights and margins don't align to the grid | Use the 8px grid for all vertical measurements |
Quick Reference
Spacing Decision Tree
What are you spacing?
1. Text line to text line → line-height (1.5-1.6 for body)
2. Label to its input → 4-8px
3. Input to next input → 16-20px
4. Group to group → 24-32px
5. Section to section → 48-120px (responsive)
6. Inside a card → 16-24px padding
7. Between cards → 16-24px gap
8. Page side margins → 16px mobile, 24-48px desktop
Key Takeaways
- Use the 8px grid. All spacing, sizing, and positioning should be multiples of 8 (with 4px for micro adjustments).
- Define spacing tokens and use them everywhere. Never use arbitrary pixel values in code.
- Space within groups < space between groups < space between sections. This creates visual hierarchy.
- Use CSS Grid with
auto-fillandminmax()for responsive card layouts without breakpoints. - Increase spacing proportionally at larger screen sizes. Don't just make content wider.
- Prefer
gapovermarginfor spacing between flex/grid children. - When in doubt, add more whitespace. Beginners consistently use too little.
- Set a max-width container. No content should span 100% of a 2560px monitor.