CSS :hover does not fire reliably on touch devices — there is no cursor, so hover states either never trigger or trigger on first tap and then persist, breaking the interaction model. Dropdown menus that only open on hover are completely inaccessible on touch screens. Tooltips that only appear on hover convey information that touch and keyboard users never receive — a WCAG 2.2 SC 2.1.1 (Keyboard) and SC 1.4.13 (Content on Hover or Focus) violation. The practical business impact is that users on iPhone or Android simply cannot reach menu items, card actions, or contextual controls gated behind hover states.
High because hover-only functionality is completely unreachable on touch devices, locking out the majority of mobile users from affected features.
Convert hover-gated interactions to explicit click/tap handlers. Replace pure CSS hover dropdowns with a controlled open/close state:
const [open, setOpen] = useState(false)
return (
<div
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
onClick={() => setOpen(o => !o)}
>
<button aria-expanded={open}>{label}</button>
{open && <DropdownMenu />}
</div>
)
For card action overlays, ensure they are always visible on mobile via src/app/globals.css:
.card-actions { opacity: 0; transition: opacity 0.15s; }
.card:hover .card-actions { opacity: 1; }
@media (max-width: 640px) { .card-actions { opacity: 1; } }
ID: mobile-responsiveness.touch.no-hover-only
Severity: high
What to look for: Search for hover-dependent interactions: dropdown menus that reveal only on :hover, tooltips shown only on mouseover, content hidden by default and revealed only on hover, and action buttons that appear only when hovering a card or list item. Look for CSS using :hover to toggle visibility with no corresponding touch or click alternative.
Pass criteria: Count all CSS :hover rules that toggle visibility, opacity, or display of interactive content (dropdown menus, tooltips, action buttons, submenus). For each hover-dependent interaction, verify it has a click/tap alternative, a keyboard alternative, or a CSS media query that makes the content always visible at mobile widths (<=640px). Report: "X hover-dependent interactions found; X of X have touch/mobile alternatives." Do NOT pass when any hover-dependent interaction lacks both a click/tap handler and a mobile visibility media query. The CSS-only media query approach is a valid solution — no click handler required if the content is always visible on touch devices.
Fail criteria: At least 1 dropdown menu, tooltip, or action is only exposed via CSS :hover with no touch/click equivalent and no CSS media query that makes the content always visible at mobile widths.
Skip (N/A) when: Never.
Detail on fail: "Dropdown navigation in components/navbar.tsx uses CSS :hover to show submenus with no JavaScript click handler or mobile fallback — 1 of 4 hover interactions inaccessible on touch".
Remediation: Pair hover states with click/tap handlers:
const [open, setOpen] = useState(false)
return (
<div
onMouseEnter={() => setOpen(true)}
onMouseLeave={() => setOpen(false)}
onClick={() => setOpen(!open)}
>
{/* ... */}
</div>
)
For card actions, make them always visible on mobile:
.card-actions { opacity: 0; }
.card:hover .card-actions { opacity: 1; }
@media (max-width: 640px) { .card-actions { opacity: 1; } }