算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
fitts-law-touch-targets【设计与创意】Use this skill when designing for touch — phones, tablets, kiosks, in-car displays, smart-TV remotes, anything where the input is a finger or thumb rather than a precise pointer. Trigger when sizing buttons for mobile, debugging "users keep mistapping," designing a mobile bottom-nav, picking icon sizes for a phone toolbar, or reviewing whether a desk…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
fitts-law; read that first if you haven''t already.'The finger is a much wider, much less precise pointer than a mouse cursor. Fitts's Law still applies, but the constants change dramatically — and a few touch-specific phenomena (occlusion, thumb reach, edge gestures) layer on top. This skill covers the practical rules.
Every major touch platform publishes a recommended minimum. They converge:
| Platform / spec | Minimum target | Notes |
|---|---|---|
| Apple HIG (iOS) | 44×44 pt | The most-cited number; matches average finger contact. |
| Material Design (Android) | 48×48 dp | Roughly equivalent to Apple's 44pt at common densities. |
| Microsoft (Windows touch) | 40×40 effective px | Slightly smaller; Microsoft's research basis. |
| WCAG 2.5.5 (Level AAA) | 44×44 CSS px | Strictest accessibility minimum. |
| WCAG 2.5.8 (Level AA, 2.2) | 24×24 CSS px (with adequate spacing) | Newer, more lenient minimum. |
The practical rule: 44×44 CSS pixels for any touchable element. This is the safe number across platforms and accessibility levels. Going smaller is occasionally defensible in specific dense expert contexts; never as a default.
The visible icon inside the button can be smaller (16–24px is common). The hit area — the actual touchable region — is what 44×44 measures.
/* Right: a small icon with a generous tap area */
.icon-button {
display: inline-grid;
place-items: center;
width: 44px;
height: 44px;
padding: 10px; /* keeps icon centered while tap area stays at 44 */
border: 0;
background: transparent;
border-radius: 22px;
}
.icon-button svg { width: 20px; height: 20px; }
Fitts's Law is about acquiring one target. When targets are clustered, spacing between them prevents accidental neighbor-taps. The convention:
For dense clusters (chip rows, segmented controls), increase visual differentiation: bordered, with internal padding, with adequate gap.
When a phone is held one-handed, the thumb can reach some screen regions easily and others only with strain. Research (Hoober and others) maps this:
+--------------------+
| hard | <- top of screen, far from thumb base
| hard | medium |
| medium | easy |
| medium | easy |
| medium | easy | <- bottom-right (right hand) is easiest
+--------------------+
For right-handed users, the bottom-right of the screen is easiest; the top-left is hardest. Left-handed users mirror.
Practical implications:
<!-- Bottom nav: thumb-friendly, primary destinations -->
<nav style="position: fixed; bottom: 0; left: 0; right: 0;">
<!-- 3-5 destinations, evenly spaced, 56px+ tall -->
</nav>
<!-- FAB: bottom-right for right-handed primary action -->
<button style="position: fixed; bottom: 24px; right: 24px; width: 56px; height: 56px; border-radius: 28px;">
<PlusIcon />
</button>
Once the user's finger touches the screen, it covers the target. A few consequences:
Material Design's ripple effect is a classic occlusion-mitigation: the ripple expands outward from the touch point, providing visible feedback that survives the finger's presence.
@keyframes ripple {
to { transform: scale(4); opacity: 0; }
}
.button-pressed::after {
content: '';
position: absolute;
border-radius: 50%;
background: currentColor;
opacity: 0.2;
animation: ripple 600ms;
}
Modern phones use the screen edges for system gestures (back-swipe, app-switcher, control-center). A button placed at the absolute edge competes with these gestures.
Practical rule: keep an 8–16px inset from the edges for primary interactive content. Use the system's safe-area insets for top notch and bottom home-indicator clearance:
.bottom-bar {
padding-bottom: env(safe-area-inset-bottom);
}
.top-bar {
padding-top: env(safe-area-inset-top);
}
The screen-edge Fitts-Law advantage still works for layout (a tap target abutting the edge is large in one dimension), but interaction must respect system gestures.
Touch devices have no hover. UI patterns that rely on hover-revealed actions (a row's "Edit" / "Delete" buttons that appear on cursor over) silently fail on touch. Mitigations:
Don't ship "hover to discover the action" patterns to mobile.
Anti-pattern (mouse-only):
<li class="list-item">
<span>Project Acme</span>
<button class="hover-only" style="opacity: 0;">Open</button>
</li>
<style>
.list-item:hover .hover-only { opacity: 1; }
</style>
On touch, the button is invisible — and even if you tap it, you can't see it.
Right (touch-friendly):
<li class="list-item" style="display: flex; align-items: center; padding: 12px 16px; min-height: 56px;">
<span style="flex: 1;">Project Acme</span>
<button aria-label="Open Acme" style="width: 44px; height: 44px;">
<ChevronRightIcon />
</button>
</li>
The action is always visible; the row itself meets the 44px height minimum (56px is even better).
<div class="stepper" style="display: inline-flex; align-items: center; gap: 12px;">
<button aria-label="Decrease" style="width: 44px; height: 44px;">−</button>
<input type="number" value="1" style="width: 60px; height: 44px; text-align: center;" />
<button aria-label="Increase" style="width: 44px; height: 44px;">+</button>
</div>
Both buttons are 44×44 with 12px gap to the input — generous spacing prevents misclicks.
<button class="fab" aria-label="New post" style="
position: fixed;
bottom: calc(24px + env(safe-area-inset-bottom));
right: 24px;
width: 56px; height: 56px;
border-radius: 28px;
background: var(--brand);
color: white;
display: grid; place-items: center;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
">
<PlusIcon />
</button>
Bottom-right for thumb reach. 56×56 hit area. Safe-area-inset for home-indicator clearance. Subtle shadow because FABs do float above content.
<nav class="tab-bar" style="
position: fixed; bottom: 0; left: 0; right: 0;
display: grid; grid-template-columns: repeat(5, 1fr);
height: calc(56px + env(safe-area-inset-bottom));
padding-bottom: env(safe-area-inset-bottom);
background: white;
border-top: 1px solid hsl(0 0% 90%);
">
<button class="tab" aria-current="page">
<HomeIcon style="width: 24px; height: 24px;" />
<span style="font-size: 10px;">Home</span>
</button>
<!-- four more tabs -->
</nav>
<style>
.tab {
display: grid; place-items: center; gap: 2px;
border: 0; background: transparent;
color: hsl(0 0% 50%);
}
.tab[aria-current="page"] { color: var(--brand); }
</style>
5 tabs across the bottom. Each tab gets ~76px width × 56px height — generously above 44×44.
fitts-law (parent).fitts-law-screen-edges — companion for desktop; some overlap on mobile (safe areas).affordance (parent plugin) — touch targets need visual affordance to be discoverable.accessibility-operable (process plugin) — touch target sizes are an accessibility minimum; don't go below.