👆 Touch Interface Design

Touchscreens lack the precision of a mouse cursor. We must design for "fat fingers" and imprecise taps. A frustrating touch experience leads to immediate abandonment.

1. The 44px Minimum Touch Target Rule

Apple's Human Interface Guidelines recommend a minimum hit area of 44×44 points (approximately 44px at 1×). Google Material Design recommends 48×48dp. The underlying reason is the same: the average adult fingertip contact area is approximately 10mm, which translates to 44–48px at common screen densities.

This rule applies to the interactive area, not necessarily the visible element. A small icon can have a larger invisible tap region created with padding:

Hard to tap accurately

Easy to tap every time

/* Expand tap area without changing visual size */
.icon-button {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px;  /* Creates tap area around the 24px icon */
}

/* Alternatively, extend tap area with pseudo-element */
.small-link::after {
  content: '';
  position: absolute;
  inset: -10px;  /* Extend 10px in all directions */
}

Common Violations on Psilobase

  • Close buttons (×) on modals: Often styled as small text. Wrap in a 44px container.
  • TOC links: List items in a compact table of contents. Add sufficient padding to each anchor.
  • Breadcrumb separators: The arrow ">" should not itself be tappable, but the text links on either side must meet size requirements.
  • Form checkboxes and radio buttons: Native elements are often only 16–20px. Extend via label padding or a custom component.

2. Spacing Between Interactive Elements

Even correctly-sized targets can cause accidental taps if they are placed too close together. The minimum gap between adjacent interactive elements is 8px, but 12–16px is preferable, especially for destructive actions (delete, clear form).

High-Risk Areas

  • Navigation menus: Mobile nav items in a list need at least 44px height per item and 8px visual separation. Full-width list items remove the horizontal crowding problem entirely.
  • Tag clouds / filter chips: When multiple small filter badges appear inline, they quickly crowd together. Wrap them with gap: 8px and ensure each chip is ≥ 36px tall (accept 36px for very small utility chips).
  • Social share buttons: Groups of 4–5 small icons. Use a flex container with gap: 12px and ensure each button is 44px.
  • Pagination controls: Previous / Next buttons alongside numbered pages. On mobile, consider a simplified "Page X of Y" pattern instead of showing all page numbers.
/* Safe spacing for button groups */
.button-group {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.button-group button {
  min-height: 44px;
  padding: 0 20px;
}

3. Touch Gestures

Beyond the basic tap, mobile users expect certain gesture conventions. Implementing them correctly creates a native-app-like feel; violating them creates frustration.

Swipe

Horizontal swipe is expected for carousels, image galleries, and off-canvas drawers (hamburger menus). Vertical swipe scrolls the page — never hijack vertical scroll for custom behaviour, as this disorients users deeply.

  • Implement carousels with scroll-snap in CSS for a performant, gesture-native feel without JavaScript event overhead.
  • Off-canvas menus should use a touch-pan-x gesture with touch-action: pan-y on the menu itself to avoid conflicting with vertical page scroll.

Pinch-to-Zoom

Never set user-scalable=no in the viewport meta tag. This violates WCAG 1.4.4 (Resize Text) and is inaccessible to users with low vision. It also frustrates users trying to examine small images (species photos, diagram details).

<!-- NEVER DO THIS -->
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">

<!-- CORRECT -->
<meta name="viewport" content="width=device-width, initial-scale=1">

Long Press

Long press (press and hold for 500–700ms) triggers native browser behaviour: text selection, image save menu, link preview. Do not override this. Custom long-press interactions are rarely discoverable and confuse users.

Pull-to-Refresh

On mobile Chrome, pulling down from the top of the page triggers a native pull-to-refresh. If your page uses an infinite scroll or auto-update mechanism, this can conflict. Disable with overscroll-behavior-y: contain on the scrollable element if needed.

4. Visual Feedback on Touch

Touchscreens have no hover state. The only feedback states available are :focus (via keyboard) and :active (while the finger is down). Without immediate feedback, users assume the tap didn't register and tap again.

/* Active state feedback */
button:active,
a:active {
  transform: scale(0.97);
  opacity: 0.85;
  transition: transform 0.1s ease, opacity 0.1s ease;
}

/* Remove tap highlight on mobile (replace with custom :active) */
* {
  -webkit-tap-highlight-color: transparent;
}

Loading States

If a tap triggers a network request (search, form submit, navigation to a slow page), show a loading indicator within 100ms of the tap. Without this, users cannot tell if the tap registered. A spinner, skeleton screen, or progress bar all work — the key is immediacy.

Haptic Feedback

On supported devices, the Vibration API can provide subtle tactile confirmation for important actions. Use sparingly — only for high-stakes confirmations (form submit, safety checklist complete).

// Subtle haptic on form submit (50ms vibration)
submitButton.addEventListener('click', () => {
  if ('vibrate' in navigator) {
    navigator.vibrate(50);
  }
});

5. Scroll and Overflow Behaviour

Horizontal overflow is one of the most common mobile layout bugs. A single element wider than the viewport causes the entire page to scroll horizontally, which is highly disorienting.

  • Images: Always set max-width: 100% on all images to prevent overflow.
  • Code blocks and tables: These legitimately need horizontal scroll. Wrap them in overflow-x: auto containers rather than letting them break the page.
  • Long URLs and strings: Use word-break: break-word or overflow-wrap: break-word on content areas to prevent long strings from overflowing.

Momentum Scrolling on iOS

Scrollable containers on iOS require -webkit-overflow-scrolling: touch (legacy) or the modern equivalent for smooth momentum-based scrolling. Native page scroll is always momentum-enabled; custom scrollable elements (modals, sidebars) may not be.

/* Smooth scroll for custom scrollable containers on iOS */
.modal-content,
.sidebar-scroll {
  overflow-y: auto;
  overscroll-behavior: contain;  /* Prevent scroll chaining */
  -webkit-overflow-scrolling: touch;
}

6. Form Inputs on Touch Devices

Mobile keyboards and input behaviour differ significantly from desktop. Failing to account for this creates poor experiences in the site search, contact forms, and any dosage calculators.

  • Input type: Always use the correct type attribute to summon the appropriate keyboard. type="email" shows the @ key; type="number" shows the numeric pad; type="tel" shows the phone dial pad.
  • inputmode: For fine-grained control: inputmode="decimal" on a type="text" field shows a decimal numeric keyboard without the browser's built-in number input restrictions.
  • Font size on iOS: If an input's font-size is below 16px, iOS Safari automatically zooms in on focus, then fails to zoom back out. Set all inputs to font-size: 16px minimum.
  • Autocomplete: Use autocomplete attributes to help password managers and autofill reduce typing burden on mobile.
<!-- Good mobile form input -->
<input
  type="text"
  inputmode="decimal"
  autocomplete="off"
  style="font-size: 16px; min-height: 44px; padding: 0 12px;"
  placeholder="Enter amount in grams"
>

📅 Created: 25 January 2026 | ✍️ Author: Mobile UX Team | 🔄 Next Review: July 2026