Mobile: every interactive control is below the 44x44 minimum tap target #43

Closed
opened 2026-08-09 16:50:35 +02:00 by clawbot · 3 comments
Collaborator

Found by the responsive-layout harness added for #13
(make frontend-viewport-test). Fails at all four touch viewports tested.

Threshold used: 44x44 CSS px, from Apple's Human Interface Guidelines and
WCAG 2.2 SC 2.5.5 "Target Size (Enhanced)". WCAG 2.2 SC 2.5.8 (AA) allows a
lower 24x24 floor, but only with a spacing exception these controls do not
qualify for — the pin button sits directly against the host name it belongs to.

Measured, narrow layout

Control Size Count Assessment
.pin-btn 16x16 26 clearly unusable on touch
#debug-toggle 89.3x14 1 label is wide but 14px tall
#interval-select 64x28 1 passes AA 24x24, misses 44x44
#pause-btn 108.2x39.8 1 marginal — 4.2px short

At wide viewports the pause button passes; the other three fail there too, and
the landscape-above-breakpoint viewport (844x390) is still a touch device, so
they matter there as well.

Notes on intent

The max-width: 768px block in src/styles.css deliberately shrinks
#pause-btn to padding: 0.5rem 1rem. That choice is not the problem — it just
lands 4.2px under the line, and a slightly taller padding would clear it. The
pin button and the debug-log checkbox label look like straightforward
oversights: the pin button is a bare 16x16 SVG in a button with no padding at
all.

Fixing this is cosmetic-to-easy (padding, or a larger hit area via a
pseudo-element) and does not require changing the visual design. Once fixed,
make frontend-viewport-test will report tap-targets-44px passing; it
currently names every offender and its measured size on failure.

Ref #13, #5, #2

Found by the responsive-layout harness added for #13 (`make frontend-viewport-test`). Fails at all four touch viewports tested. Threshold used: **44x44 CSS px**, from Apple's Human Interface Guidelines and WCAG 2.2 SC 2.5.5 "Target Size (Enhanced)". WCAG 2.2 SC 2.5.8 (AA) allows a lower 24x24 floor, but only with a spacing exception these controls do not qualify for — the pin button sits directly against the host name it belongs to. ## Measured, narrow layout | Control | Size | Count | Assessment | | ------------------ | ------------- | ----- | ------------------------------------- | | `.pin-btn` | 16x16 | 26 | clearly unusable on touch | | `#debug-toggle` | 89.3x14 | 1 | label is wide but 14px tall | | `#interval-select` | 64x28 | 1 | passes AA 24x24, misses 44x44 | | `#pause-btn` | 108.2x39.8 | 1 | marginal — 4.2px short | At wide viewports the pause button passes; the other three fail there too, and the landscape-above-breakpoint viewport (844x390) is still a touch device, so they matter there as well. ## Notes on intent The `max-width: 768px` block in `src/styles.css` deliberately shrinks `#pause-btn` to `padding: 0.5rem 1rem`. That choice is not the problem — it just lands 4.2px under the line, and a slightly taller padding would clear it. The pin button and the debug-log checkbox label look like straightforward oversights: the pin button is a bare 16x16 SVG in a button with no padding at all. Fixing this is cosmetic-to-easy (padding, or a larger hit area via a pseudo-element) and does not require changing the visual design. Once fixed, `make frontend-viewport-test` will report `tap-targets-44px` passing; it currently names every offender and its measured size on failure. Ref #13, #5, #2
Author
Collaborator

On the 44x44 threshold — read before implementing

The harness uses 44x44 (Apple HIG, WCAG 2.2 SC 2.5.5 Target Size Enhanced, AAA). WCAG also defines a AA floor of 24x24 (SC 2.5.8 Minimum). Which one applies changes the size of this fix substantially: at 24x24 most of this issue evaporates.

Recommendation: keep 44x44 for the standalone controls, and treat the 26 per-row pin buttons as the open question.

  • #pause-btn (108.2x39.8), #interval-select (64x28) and the debug-log label (89.3x14) are singular controls with room around them. Padding them to 44 high is cheap and there is no argument for a lower bar.
  • .pin-btn at 16x16, times 26 rows, is the hard one. Enforcing 44x44 there adds 28px of height per row across the whole list, which may materially damage the dense at-a-glance layout that is the point of this app. If it does, 24x24 with adequate spacing is a defensible AA-conformant fallback for that control specifically.

Do the standalone controls at 44 unconditionally. For the pin buttons, try 44 first and measure the layout cost; if it wrecks the density, drop that one control to 24 and say so in the PR with the before/after row height, rather than lowering the harness constant globally.

If you lower the threshold, it must be per-selector in the harness with a comment naming the standard and the reason — not a single constant change that silently relaxes the bar for everything.

Escalate to @sneak only if you think the whole harness should move to the AA floor; that is a product call, not an implementation detail.

## On the 44x44 threshold — read before implementing The harness uses 44x44 (Apple HIG, WCAG 2.2 SC 2.5.5 Target Size Enhanced, **AAA**). WCAG also defines a **AA** floor of 24x24 (SC 2.5.8 Minimum). Which one applies changes the size of this fix substantially: at 24x24 most of this issue evaporates. **Recommendation: keep 44x44 for the standalone controls, and treat the 26 per-row pin buttons as the open question.** - `#pause-btn` (108.2x39.8), `#interval-select` (64x28) and the debug-log label (89.3x14) are singular controls with room around them. Padding them to 44 high is cheap and there is no argument for a lower bar. - `.pin-btn` at 16x16, times 26 rows, is the hard one. Enforcing 44x44 there adds 28px of height per row across the whole list, which may materially damage the dense at-a-glance layout that is the point of this app. If it does, 24x24 with adequate spacing is a defensible AA-conformant fallback for that control specifically. Do the standalone controls at 44 unconditionally. For the pin buttons, try 44 first and measure the layout cost; if it wrecks the density, drop that one control to 24 and **say so in the PR with the before/after row height**, rather than lowering the harness constant globally. If you lower the threshold, it must be per-selector in the harness with a comment naming the standard and the reason — not a single constant change that silently relaxes the bar for everything. Escalate to @sneak only if you think the whole harness should move to the AA floor; that is a product call, not an implementation detail.
Author
Collaborator

Plan

Keeping 44x44 for all four controls, including .pin-btn — no per-selector relaxation needed, because the pin button's hit area can grow without costing a single pixel of row height.

  • .pin-btn: width/height: 2.75rem with margin: -0.875rem on all sides and the icon centred. The button's border box becomes 44x44 while its layout footprint stays the 16x16 the 16x16 SVG occupied, so the wide layout is byte-identical in geometry and the narrow layout (where the button is position: absolute) keeps the icon at exactly the same coordinates. Row density is unchanged; no fallback to the AA 24x24 floor.
  • #interval-select: min-height: 2.75rem. A select renders its own background and border, so the negative-margin trick would visibly enlarge it — this one genuinely gets taller.
  • debug-log label (the element the harness measures for #debug-toggle): inline-flex + min-height: 2.75rem.
  • #pause-btn: min-height: 2.75rem inside the existing max-width: 768px block; it is 4.2px short there and already passes wide.

Applied unconditionally rather than under (pointer: coarse), since the 844x390 landscape viewport is above the breakpoint and still a touch device.

Verification: throwaway merge of origin/feat/viewport-harness (#44) in a scratch clone, running make frontend-viewport-test at every viewport; the harness itself is not touched and none of its files land on this branch.

## Plan Keeping 44x44 for all four controls, including `.pin-btn` — no per-selector relaxation needed, because the pin button's hit area can grow without costing a single pixel of row height. - `.pin-btn`: `width/height: 2.75rem` with `margin: -0.875rem` on all sides and the icon centred. The button's border box becomes 44x44 while its *layout* footprint stays the 16x16 the 16x16 SVG occupied, so the wide layout is byte-identical in geometry and the narrow layout (where the button is `position: absolute`) keeps the icon at exactly the same coordinates. Row density is unchanged; no fallback to the AA 24x24 floor. - `#interval-select`: `min-height: 2.75rem`. A `select` renders its own background and border, so the negative-margin trick would visibly enlarge it — this one genuinely gets taller. - debug-log `label` (the element the harness measures for `#debug-toggle`): `inline-flex` + `min-height: 2.75rem`. - `#pause-btn`: `min-height: 2.75rem` inside the existing `max-width: 768px` block; it is 4.2px short there and already passes wide. Applied unconditionally rather than under `(pointer: coarse)`, since the 844x390 landscape viewport is above the breakpoint and still a touch device. Verification: throwaway merge of `origin/feat/viewport-harness` (https://git.eeqj.de/sneak/netwatch/pulls/44) in a scratch clone, running `make frontend-viewport-test` at every viewport; the harness itself is not touched and none of its files land on this branch.
Author
Collaborator

Implemented in #51 (branch fix/mobile-tap-targets, base next), commit 46e90a7.

All four controls hold 44x44; no fallback to the AA 24x24 floor, and the harness is untouched.

Verified with make frontend-viewport-test in a throwaway scratch clone that merges #44 on top of the branch (no harness file lands here). tap-targets-44px goes FAIL to PASS at every touch viewport: 320x568, 667x375, 767x1024, 768x1024, 769x1024, 844x390 — 29 controls measured, all at least 44x44. Harness total 47/55 checks to 53/55; desktop 1280x800 stays 7/7.

Row density is unchanged and measured, not asserted: the harness's per-row geometry is identical before and after at all seven viewports. The two remaining failures at 320x568 are pre-existing .status-text overflow, i.e. #42.

make check green.

Implemented in https://git.eeqj.de/sneak/netwatch/pulls/51 (branch `fix/mobile-tap-targets`, base `next`), commit `46e90a7`. All four controls hold 44x44; no fallback to the AA 24x24 floor, and the harness is untouched. Verified with `make frontend-viewport-test` in a throwaway scratch clone that merges https://git.eeqj.de/sneak/netwatch/pulls/44 on top of the branch (no harness file lands here). `tap-targets-44px` goes FAIL to PASS at every touch viewport: 320x568, 667x375, 767x1024, 768x1024, 769x1024, 844x390 — 29 controls measured, all at least 44x44. Harness total 47/55 checks to 53/55; desktop 1280x800 stays 7/7. Row density is unchanged and measured, not asserted: the harness's per-row geometry is identical before and after at all seven viewports. The two remaining failures at 320x568 are pre-existing `.status-text` overflow, i.e. https://git.eeqj.de/sneak/netwatch/issues/42. `make check` green.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/netwatch#43