原生title属性在表格单元格和禁用按钮中完全失效,因主流屏幕阅读器忽略其语义,且缺乏触发关系、生命周期与焦点上下文;必须用aria-describedby+role="tooltip"+javascript焦点管理实现可访问提示。

原生 title 属性无法满足可访问性要求,必须用 aria-describedby + role="tooltip" + JavaScript 焦点管理组合实现,否则屏幕阅读器读不到、键盘用户无法触发、移动端无响应。
为什么title在表格和禁用按钮中完全失效
主流屏幕阅读器(NVDA、JAWS、VoiceOver)在 <td> 或 <code><button disabled></button> 上基本忽略 title。这不是兼容性问题,而是语义缺失:它没有明确的触发关系、生命周期或焦点上下文。
-
<td title="Success">✓</td>→ VoiceOver 通常静默跳过,不朗读 -
<button disabled title="暂不可用">提交</button>→ 悬停无效、Tab 焦点跳过、title不被解析为提示 - 即使加了
role="tooltip"到<td> 或 <code><button></button>,也属于 ARIA 误用——role="tooltip"必须是独立、动态显示/隐藏的元素,且需通过aria-describedby显式关联aria-describedby关联必须严格匹配 ID 引用这是最常出错的一环:ID 大小写、空格、重复、未渲染就绑定,都会导致屏幕阅读器完全“失联”。
- 触发元素上写
aria-describedby="my-tip",对应提示元素必须有id="my-tip"(不能是class="my-tip"或data-id="my-tip") - ID 值不能含空格或特殊字符,推荐纯字母数字,如
tip-user-status-123 - 若提示内容由 JS 动态插入,必须等 DOM 渲染完成后再设置
aria-describedby,否则初始状态为空引用 - 一个元素只能关联一个 tooltip ID;多个提示需拆成多个独立
id+ 多个aria-describedby(不支持逗号分隔)
键盘交互必须覆盖 Tab 进入、Esc 关闭、焦点保持
仅靠
:hover和:focus的纯 CSS 方案,在键盘导航下是残缺的:无法按 Tab 进入提示、Esc 无法关闭、焦点丢失后提示残留。- 触发元素必须设
tabindex="0"(即使是<div> 或 <code><span></span>),否则键盘无法抵达 - 监听
focus和blur事件控制aria-hidden="false"/true,而非只依赖:focus伪类 - 监听
keydown,当按下Escape时主动隐藏 tooltip 并将焦点返回触发元素 - tooltip 元素本身要设
tabindex="-1",确保它可被focus()聚焦但不参与自然 Tab 顺序——这对屏幕阅读器朗读起始点很关键 - 不要把交互逻辑绑在
.trigger:hover .tooltip上——这在触摸设备上大概率不执行 - 改用
click+touchstart双事件监听,或统一用pointerdown(兼容鼠标/触摸/笔) - 对
<button disabled></button>这类无法直接绑定事件的元素,必须在外层包裹容器(如<span class="disabled-wrapper"></span>),并在该容器上监听事件 - 避免使用
ontouchstart全局阻止默认行为,否则可能干扰页面滚动
移动端和触摸设备必须放弃
:hover依赖iOS Safari 对
:hover支持极不稳定:轻触只触发一次,后续需先点空白处再点目标才生效;Android 表现也不一致。纯 CSS tooltip 在真机上基本不可靠。真正可访问的 tooltip 不是“加上 ARIA 就完事”,而是让每个交互路径(鼠标悬停、Tab 焦点、点击、触摸、Esc 关闭)都有一致的行为闭环,并且所有 DOM 引用、状态切换、焦点转移都经过显式控制——漏掉任意一环,对某类用户就是不可用。
- 触发元素上写











