| name | mobile |
| description | Mobile-first patterns - forms, thumb zones, responsive |
Luke Wroblewski - Mobile-First Patterns
Design for mobile constraints first. Desktop is mobile with more space.
Core Philosophy
Mobile First
Start with the smallest screen, then add. Don't start big and remove.
Why:
- Forces prioritization (no room for clutter)
- Mobile is the hard problem (desktop is easy)
- Touch constraints are stricter
- Performance matters more
Forms are Conversations
Forms are not data entry. They're conversations with users.
Mobile Form Patterns
Input Types
<input type="email">
<input type="tel">
<input type="number">
<input type="url">
<input type="search">
<input type="date">
Top-Aligned Labels
<div class="field">
<label for="email">Email address</label>
<input type="email" id="email">
</div>
.field label {
display: block;
margin-bottom: 4px;
font-size: 14px;
font-weight: 500;
}
.field input {
width: 100%;
min-height: 44px;
}
Inline Validation
input.addEventListener('blur', validateField);
function showValidation(field, isValid) {
field.classList.remove('error', 'success');
field.classList.add(isValid ? 'success' : 'error');
}
Smart Defaults
<input type="tel" autocomplete="tel">
<input type="email" autocomplete="email">
<select>
<option selected>United States</option>
</select>
<input type="date" value="2024-01-15">
Prescriptive Form Rules
Field Order
1. Required fields first
2. Related fields grouped
3. Optional fields last (or behind "Show more")
4. Never ask for info you can infer
Reducing Input
DON'T DO
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Name: [First] [Last] โ Name: [Full name]
Address line 2 โ (Remove - rarely used)
Country dropdown โ (Auto-detect from IP)
Confirm email โ (Just show what they typed)
Phone format โ (Accept any format, parse)
Error Messages
<span class="error">Invalid input</span>
<span class="error">
<svg></svg>
Enter a valid email like name@example.com
</span>
Rules:
- Specific, not generic
- Show what valid looks like
- Place below the field
- Don't clear the input (let them fix it)
Mobile Navigation
Bottom Navigation (Primary)
<nav class="bottom-nav">
<a href="/" class="nav-item active">
<svg></svg>
<span>Home</span>
</a>
<a href="/search" class="nav-item">
<svg></svg>
<span>Search</span>
</a>
<a href="/profile" class="nav-item">
<svg></svg>
<span>Profile</span>
</a>
</nav>
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
background: white;
border-top: 1px solid var(--gray-200);
padding-bottom: env(safe-area-inset-bottom);
}
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 8px;
min-height: 56px;
}
Rules:
- Maximum 5 items
- Icons + labels (not just icons)
- Active state visible
- Safe area for notch devices
Hamburger Alternative
Instead of hidden menus, use:
- Bottom navigation (most common actions)
- Tab bar (content categories)
- Priority+ pattern (show what fits, ... for rest)
<nav class="priority-nav">
<a href="/home">Home</a>
<a href="/products">Products</a>
<a href="/about">About</a>
<button class="more">More...</button>
</nav>
Responsive Breakpoints
.container {
padding: 16px;
}
@media (min-width: 640px) {
.container {
padding: 24px;
}
}
@media (min-width: 1024px) {
.container {
padding: 32px;
max-width: 1200px;
margin: 0 auto;
}
}
Content Adaptation
| Mobile | Tablet | Desktop |
|---|
| Stack (1 col) | 2 columns | 3-4 columns |
| Bottom nav | Bottom nav or sidebar | Sidebar |
| Full-width cards | Card grid | Card grid with filters |
| Single action | Multiple actions visible | All actions visible |
Touch Targets
.touch-target {
min-width: 44px;
min-height: 44px;
}
.button + .button {
margin-left: 8px;
}
a.touch-target {
padding: 12px;
margin: -12px;
}
Performance Rules
1. Critical CSS inline
2. Images lazy-loaded
3. Font loading: swap (show text immediately)
4. No blocking resources
5. First meaningful paint < 1.5s on 3G
<img src="placeholder.jpg" data-src="real-image.jpg" loading="lazy">
<link rel="preload" href="font.woff2" as="font" crossorigin>
Review Checklist
Anti-Patterns
| Bad | Why | Fix |
|---|
| Labels beside inputs | Hard on narrow screens | Labels above |
| Hamburger for primary nav | Hidden = unused | Bottom nav |
| Placeholder as label | Disappears on input | Real label |
| Dropdown for < 5 options | Requires two taps | Radio buttons |
| Confirm password field | Annoying, little value | Show/hide toggle |
| Country dropdown first | Rare use case | Auto-detect, last |
Wroblewski Score
| Score | Meaning |
|---|
| 10 | Mobile-native, forms are effortless |
| 7-9 | Works on mobile but desktop-first thinking |
| 4-6 | Pinch/zoom required, forms painful |
| 0-3 | Unusable on mobile |
Integration
Combine with:
/interaction - Input fundamentals these patterns build on
/usability - Psychology of form completion
/components - Components that implement these patterns