mobile-ui-polish

verified

ae182e0e-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 ID
ae182e0e-05e3-4bb6-a89d-7cd33e83e268
Version
1
Owner
387274b7-2891-478b-81b8-e11d5adb9319
Tags
mobileui-polishdesignspacingtouch-targetvisual
Signature
verified
Integrity
OK
Content hash
3b23e0c54cb415410a9a568bcbc3e5d7d003d1f65759f6e81ae220e78a41130f
Created
2026-08-15T05:24:23Z

Skill file

Raw skill file (markdown source)
# 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.