触摸目标必须 ≥48×48px,即元素实际渲染后的 clientwidth 和 clientheight 均不得小于 48px;常见错误包括 overflow 裁剪、transform 缩放不改变尺寸、行内元素塌陷;应显式设置 min-width/min-height、使用语义化标签、避免 role="button" 伪解法、控制 dom 深度 ≤6、优先用 pointerdown 而非 touchstart。

触摸目标必须 ≥48×48px,不是“看起来够大”就行
很多团队在真机上测出按钮点不中、VoiceOver跳过某个“按钮”,第一反应是“加个 aria-label 就行”,但问题根本不在标签——而是浏览器压根没把它识别为可触控元素。WCAG 2.2 和 iOS/Android 官方指南都明确要求最小触控区域为 48px × 48px(CSS 像素),且这个尺寸必须是元素实际渲染后的 clientWidth 和 clientHeight,不是靠 font-size + padding 算出来的视觉大小。
常见错误包括:
-
overflow: hidden裁剪了 padding 区域,导致 clientHeight 不达标 - 用
transform: scale(1.2)放大图标,但 clientWidth 仍是原始值 -
display: inline的<a></a>或<span></span>受line-height挤压,上下点击区塌陷
实操建议:
- 所有可交互元素(
<button></button>、<a></a>、<input type="checkbox">)显式设置min-width: 48px和min-height: 48px - 确保它是块级或
display: inline-block,避免行内元素的渲染塌陷 - 用 Chrome DevTools 的「Toggle device toolbar」+「Inspect」直接看 computed
width/height,别信设计稿标注
别用 padding 兜底,min-width/min-height 才是硬约束
仅靠 padding: 12px + font-size: 16px 拼出的按钮,在 iOS WebView 或旧版 Android 浏览器里常被判定为 36px × 36px,因为 line-height 和字体基线会吃掉部分高度。浏览器判断可触控性时,只认 clientWidth × clientHeight,而这个值受 transform、scale、overflow 影响极大。
图标按钮尤其危险:一个 <button><svg width="24" height="24"></svg></button>,即使加了 padding: 12px,若没设 min-width/min-height,实测 clientWidth 往往只有 40px 左右。
实操建议:
- 对纯图标按钮,强制写
min-width: 48px; min-height: 48px;,不要依赖 padding 推算 - 相邻可触元素之间留至少
8px间距,否则 iOS VoiceOver 滑动切换焦点时易连跳 - 禁用
touch-action: none在按钮上——它会让整个元素失去触控可达性,哪怕尺寸达标
用原生语义标签,而不是 role="button" 伪装
role="button" 是移动端可访问性最典型的“伪解法”。它不支持键盘 Enter/Space 触发,不响应 :active 状态,部分 WebView 中完全不进焦点流。用户双指滑动时,VoiceOver 会直接跳过这类元素,但 JS 逻辑可能已执行——造成“点了没反馈,但表单已提交”的诡异现象。
真正有效的做法,是让 DOM 结构本身具备语义和行为能力:
- 把
<div class="btn" onclick="submit()"></div>换成<button type="button" onclick="submit()"></button> -
<label></label>必须显式包裹<input type="checkbox">,或用for属性绑定id,否则点击文字无法触发 - 禁用任何带
onclick的<div> 或 <code><span></span>,它们在 DOM 深度 >6 层时,touchstart延迟会飙升DOM 深度控制在 ≤6 层,不只是为了性能——更深的嵌套会让屏幕阅读器“摸不到”底层元素,焦点流断裂。
touchstart不能替代click,优先用pointerdown为防 300ms 延迟而全局替换
click为touchstart,会直接破坏键盘导航和屏幕阅读器支持。更糟的是,touchstart在手指刚接触屏幕就触发,极易误触;而touchend又缺乏鼠标兼容性。现代方案是用
pointerdown:- 它天然兼容触控 / 鼠标 / 笔输入,无 300ms 延迟,且语义更接近“按下”动作
- 所有主流浏览器(Chrome 55+、Safari 13+、Firefox 59+)均已支持
- 无需
event.preventDefault(),不会干扰滚动或缩放
如果必须用
touchstart:- 限定在导航容器内监听,别绑到
document级,避免冒泡冲突 - 必须补
keydown监听(Enter/Space),否则键盘用户完全无法操作 - 加
role="button"的同时,必须同步管理aria-pressed状态,否则 VoiceOver 读不出当前状态
真正的难点从来不在“怎么让按钮变大”,而在于让浏览器和辅助技术都一致认为:“这个东西,就是能点的”。尺寸只是表象,语义、DOM 结构、事件链长度,三者缺一不可。











