mobile-ui-polish
verifiedae182e0e-05e3-4bb6-a89d-7cd33e83e268
Polish mobile UI with designer judgment — spacing, touch targets, typography, and visual hierarchy — after functional fixes. Use when a mobile view works but looks unfinished.
Metadata
Skill file
# Mobile UI Polish
Use when a mobile interface is *functional* but looks unfinished — this is about visual quality, spacing, and hierarchy, applied with a designer's eye rather than a checklist-only approach.
## The Mobile Polish Checklist
| Element | Target | Why |
|---|---|---|
| Touch targets | ≥44×44px (Apple) / ≥48×48dp (Material) | Fingertip accuracy, reduces mis-taps |
| Base font size | ≥16px | Prevents iOS auto-zoom on input focus |
| Spacing scale | Consistent 4px or 8px grid | Visual rhythm, avoids "random" gaps |
| Primary action | One clear, prominent CTA per screen | Users know what to tap next |
| Contrast | WCAG AA (4.5:1) | Readability in sunlight |
| Tap states | Visible `:active`/pressed feedback | Confirms the tap registered |
| Safe areas | Respect notch/home-indicator | Content isn't cut off |
## Adjust-and-Compare (no guessing)
**The core discipline**: make ONE change at a real viewport, capture before/after, compare. Never batch changes.
```javascript
// In DevTools at 390×844, before changing anything:
// 1. Screenshot the current state
// 2. Make ONE change (e.g., increase button height 40px → 48px)
// 3. Screenshot again
// 4. Compare side-by-side
```
```python
# Scriptable before/after with Playwright
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={"width": 390, "height": 844})
page.goto("http://localhost:3000")
page.screenshot(path="before.png")
# Apply one change via injected CSS
page.add_style_tag(content=".primary-btn { min-height: 48px; padding: 12px 20px; }")
page.screenshot(path="after.png")
browser.close()
```
## Typography as the First Move
Typography and whitespace are the highest-leverage polish — they change perception more than color or borders.
```css
/* Establish a type scale and rhythm */
:root {
--space-1: 4px;
--space-2: 8px;
--space-3: 12px;
--space-4: 16px;
--space-5: 24px;
--space-6: 32px;
}
body {
font-size: 16px;
line-height: 1.5;
-webkit-text-size-adjust: 100%;
}
h1 { font-size: 1.5rem; margin-bottom: var(--space-4); }
h2 { font-size: 1.25rem; margin-bottom: var(--space-3); }
p { margin-bottom: var(--space-4); }
```
### Fix iOS input auto-zoom
```css
/* iOS zooms in on inputs with font-size < 16px */
input, select, textarea {
font-size: 16px;
}
```
## Touch Targets
```css
/* Ensure minimum touch target size even for small icons */
.icon-button {
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
/* Don't just make the visual bigger — expand the hit area */
.list-item {
padding: 12px 16px; /* full row is tappable */
}
```
## Visual Hierarchy Rules
1. **One primary action** — make it full-width, high-contrast, at the natural thumb position (bottom).
2. **De-emphasize secondary actions** — outline/ghost buttons, not competing solid buttons.
3. **Group related items with spacing**, not just borders. Proximity = relationship.
4. **Use `:active` states** so taps feel responsive:
```css
.primary-btn:active {
transform: scale(0.98);
background-color: #0055cc; /* slightly darker than normal */
}
```
## Guardrails
- **Never** polish at desktop width and assume mobile looks right — render at 390×844.
- **Never** batch multiple visual changes at once — you can't tell which change helped.
- **Never** break functional layout for aesthetics — if a spacing tweak overflows, revert it.
- **Never** reduce font below 16px to fit more text — that's a content problem, not a design problem.
## Pitfalls
- **Polish that breaks layout at another viewport**: Increasing padding to look good at 390px causes overflow at 320px. Test the full range after each change.
- **Subjective tweaking without a before/after**: "I think it looks better now" with no reference. Capture screenshots and compare — otherwise you're guessing and will drift.
- **Ignoring touch targets**: A visually perfect button that's 28px tall is hard to tap. Functionality and polish are linked.
- **Over-polishing**: Endless micro-adjustments ("maybe 1px more padding?"). Set a timebox (30–60 min) and a definition of done (checklist below).
- **Copy-pasting desktop spacing**: Desktop uses 24px gaps; mobile needs tighter spacing. Adjust the scale, don't inherit.
## Verify / Checklist
- [ ] All touch targets ≥44×44px (measured in DevTools, not eyeballed)
- [ ] Base font size ≥16px (no iOS auto-zoom on inputs)
- [ ] Spacing follows a consistent scale (4px/8px grid)
- [ ] One clear primary action per screen
- [ ] `:active`/pressed states visible on all interactive elements
- [ ] Contrast meets WCAG AA
- [ ] Before/after screenshots captured and compared for each change
- [ ] Layout verified at 320, 390, and 768px after all changes
- [ ] Content respects safe areas (notch / home indicator)
Attached files
No attached files.