关于 tooltips
面向包含 Tooltip 的界面开发与审查,这项无障碍技能提供选择合适交互模式、实现规范和测试方法。重点涵盖键盘、触控、辅助技术及 WCAG 要求。
主要功能
- 01判断 Tooltip 是否适用
- 02键盘与指针交互规则
- 03ARIA 关联与语义要求
- 04触控和视觉设计建议
- 05无障碍测试清单
适用场景
- 01审查组件的键盘可达性
- 02检查 Tooltip 的 ARIA 标记
- 03评估触控及放大镜访问
- 04验证悬停内容持久性
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mgifford/ accessibility-skills --skill tooltips安装后在 Claude Code 中输入/tooltips确认已加载。
附带文件SYNC.md
详细介绍
工具提示无障碍技能
权威来源:
mgifford/ACCESSIBILITY.md中的examples/TOOLTIP_ACCESSIBILITY_BEST_PRACTICES.md此技能基于该文件编写。如有疑问,以示例为准。
实现或审查工具提示组件时,请遵循这些规则。 仅当项目包含工具提示时才加载此技能。
核心要求
工具提示是简短、不可交互的描述,会在其触发元素获得键盘焦点或指针悬停时自动显示。无障碍工具提示必须能供键盘、指针、触摸、放大和辅助技术用户使用,且不得隐藏必要信息或阻挡界面。
工具提示通常并非合适的解决方案。始终可见的文本、清晰的控件标签、展开内容或对话框通常更容易发现和使用。本指南介绍由作者编写的工具提示;HTML title 属性会生成由浏览器控制的工具提示,其行为和局限有所不同(见下文)。
请使用项目的 skills/bug-reporting/SKILL.md 严重性/优先级框架对问题进行评级。以下严重性等级是本技能专用的简写,并非通用标准。
严重性等级(本技能)
| 等级 | 含义 |
|---|---|
| 严重 | 工具提示包含必要信息,且没有其他获取途径 |
| 高 | 键盘或辅助技术无法访问工具提示;工具提示中有无法脱离的交互内容 |
| 中等 | 工具提示可访问,但未完全满足 WCAG 1.4.13 要求 |
| 轻微 | 未达到最佳实践;影响较小 |
首先选择合适的模式
把所有小型弹出内容都称为工具提示,会导致语义和键盘行为不正确。请先对交互进行分类,再选择 ARIA:
| 需求 | 使用 |
|---|---|
| 控件需要更清晰的标签 | 改进其可见标签 |
| 简短的补充文本应在聚焦或悬停时自动显示 | 工具提示 |
| 完成任务需要说明或要求 | 始终可见的帮助文本 |
| 用户明确要求显示或隐藏简短帮助信息 | 由按钮控制的展开内容 |
| 弹出内容包含链接、按钮或其他控件 | 非模态对话框或其他合适的弹出模式 |
| 必须先作出决定才能继续操作 | 模态对话框或警报对话框 |
| 操作已完成或流程状态已改变 | 状态消息,而非工具提示 |
| 文本仅因布局而被截断 | 允许换行、展开,或提供其他方式以阅读完整文本 |
由作者编写的工具提示:用于描述某个元素;在聚焦或悬停后自动显示;仅包含不可交互的内容;不会获得焦点;通过 aria-describedby 与其触发元素关联;当触发元素获得焦点,或指针位于触发元素或工具提示上时保持显示;并可通过 Escape 关闭。
严重:必要信息不得仅存在于工具提示中
工具提示本质上只用于补充说明。请将说明、错误、要求和其他必要信息放在始终可见的文本中。仅通过悬停/聚焦才能看到的隐藏必要内容属于严重问题。
不得将错误消息、法律文本、安全警告或任务要求仅放在工具提示中。也不得仅将必要说明附加到已禁用的控件上——已禁用的原生表单控件可能不会触发工具提示所需的指针/焦点事件:
<p id="publish-requirement">Add a page title before publishing.</p>
<button type="button" disabled aria-describedby="publish-requirement">
Publish
</button>
高:工具提示必须在悬停和聚焦时均显示
仅在悬停时显示的工具提示属于高严重性问题——键盘用户无法触发它。焦点应保持在触发元素上;工具提示绝不能获得焦点。不要将工具提示加入 Tab 顺序,也不要使用方向键浏览其中的文本。
document.querySelectorAll('[data-tooltip]').forEach((container) => {
const trigger = container.querySelector('[data-tooltip-trigger]');
const tooltip = document.getElementById(trigger.dataset.tooltipId);
if (!tooltip || tooltip.getAttribute('role') !== 'tooltip') return;
let pointerWithin = false;
let triggerFocused = false;
let dismissed = false;
function updateTooltip() {
tooltip.hidden = !(!dismissed && (pointerWithin || triggerFocused));
}
container.addEventListener('pointerenter', () => { pointerWithin = true; dismissed = false; updateTooltip(); });
container.addEventListener('pointerleave', () => { pointerWithin = false; updateTooltip(); });
trigger.addEventListener('focus', () => { triggerFocused = true; dismissed = false; updateTooltip(); });
trigger.addEventListener('blur', () => { triggerFocused = false; updateTooltip(); });
trigger.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && !tooltip.hidden) {
dismissed = true;
updateTooltip();
event.stopPropagation();
}
});
});
分别跟踪指针状态和焦点状态——当焦点仍使工具提示保持活动状态时,却在指针离开时关闭,是常见问题。如果使用定位库,请检查其渲染的标记、焦点处理、Portal 位置、碰撞行为和清理逻辑;库的名称并不能证明其具备无障碍支持。
严重:ARIA 模式必须正确
工具提示中的 ARIA 使用不当属于严重问题——辅助技术用户会收到错误的补充信息,或无法收到补充信息。
<span class="tooltip-container" data-tooltip>
<button type="button" aria-describedby="save-tooltip"
data-tooltip-trigger data-tooltip-id="save-tooltip">
Save
</button>
<span id="save-tooltip" role="tooltip" hidden>
Saves changes to your draft.
</span>
</span>
规则:
- 工具提示元素必须具有
role="tooltip";如果触发元素会执行操作,请使用原生交互元素 作为触发元素 - 触发元素必须通过
aria-describedby引用工具提示(而非aria-labelledby);aria-describedby可以包含以空格分隔的多个 ID——添加工具提示时, 保留现有的帮助、错误或说明引用 - 使用
hidden隐藏;绝不要在活动的工具提示上使用aria-hidden="true" - 每个工具提示都必须有唯一的
id,包括重复使用的组件; 在焦点到达触发元素之前渲染描述节点 - 不要在触发元素本身上添加
role="tooltip" - 工具提示不能获得焦点——不要在工具提示容器上添加
tabindex - 不要在工具提示上添加
aria-live、role="status"或role="alert" - 不要对自动显示的工具提示使用
aria-expanded或aria-haspopup——这些属性适用于由按钮控制的展开内容,而非工具提示 - 让工具提示的文本提供可访问描述;避免使用会替换不同可见工具提示文本的
aria-label
对于仅图标的触发元素,应单独为控件命名——工具提示是描述,而不是可访问名称的替代品:
<span class="tooltip-container" data-tooltip>
<button type="button"
aria-label="Delete quarterly report"
aria-describedby="delete-tooltip"
data-tooltip-trigger data-tooltip-id="delete-tooltip">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<path d="M5 7h14M9 7V4h6v3m-8 0 1 13h8l1-13"/>
</svg>
</button>
<span id="delete-tooltip" role="tooltip" hidden>
Permanently deletes the report.
</span>
</span>
避免名称和描述完全重复相同的词语。
严重:按钮控制的帮助内容不是工具提示
当用户激活按钮以显示内容时,应使用展开模式——不要给内容添加 role="tooltip",
也不要仅仅因为内容变为可见就添加实时区域:
<button type="button" id="password-help-button"
aria-expanded="false" aria-controls="password-help">
Password requirements
</button>
<div id="password-help" hidden>
Use at least 12 characters. Include a number and a symbol.
</div>
展开状态会传达变化;焦点仍保留在按钮上。如果弹出内容包含交互控件,或必须管理焦点,请使用适当的对话框或弹出窗口模式。
中等:WCAG 1.4.13 — 悬停或聚焦时显示的内容
| 要求 | 描述 | 不符合时的严重程度 |
|---|---|---|
| 可关闭 | 按下 Escape 可关闭内容,且指针或焦点不会移动 | 严重 |
| 可悬停 | 用户可以将指针移到工具提示上,而不会使其消失 | 中等 |
| 持久显示 | 持续显示,直到触发元素或工具提示失去悬停或焦点、内容被关闭,或信息不再有效 | 中等 |
不要擅自设定自动关闭时间——只要触发元素仍处于活动状态,经过固定超时时间就消失的工具提示便不符合持久显示要求。
中等:触控与激活
触控设备无法可靠提供悬停效果。不要依赖工具提示来满足触控访问需求。可采用以下任一方式:
- 将信息显示在控件附近
- 将信息纳入控件的可访问名称或现有描述
- 提供一个单独的帮助按钮,用于打开展开内容(见上文)
- 当附加内容结构复杂或包含交互元素时,使用非模态对话框
中等:不要依赖 title 属性
当浏览器完全控制 title 工具提示的呈现方式时,它们适用 WCAG 1.4.13 的例外情形,但这并不意味着 title 是可靠的界面模式。作者无法确保 title 在键盘、触控、放大、显示时机、文本大小或关闭行为方面保持一致。不要将 title 作为以下内容的唯一方式:
- 控件的可访问名称
- 说明或验证要求的来源
- 图标说明
- 显示被截断文本的方式
- 触控用户的访问途径
中等:视觉设计
- 普通大小的工具提示文本与背景的对比度至少需要达到 4.5:1 (WCAG 1.4.3);大号文本需要达到 3:1
- 只有当视觉信息是识别组件或状态所必需时,边界、形状或箭头才需要与相邻颜色达到 3:1 的对比度(WCAG 1.4.11)——装饰性箭头并不自动受此要求约束
- 不要仅依靠颜色将工具提示与其触发器关联起来
- 在 400% 缩放和窄视口下:确保工具提示位于视口内,允许文本换行,避免水平滚动,不要遮挡触发器或关键内容,并保留关闭工具提示的方式
- 检测视口边缘并重新定位;在缩放、调整大小、内容变化和文本方向变化后重新计算位置;避免在会裁切工具提示的祖先元素内渲染
- 图标按钮触发器仍须满足 WCAG 2.2 最小目标尺寸要求
- 遵循
prefers-reduced-motion:
[role="tooltip"] {
position: absolute;
max-inline-size: min(20rem, calc(100vw - 2rem));
overflow-wrap: anywhere;
}
[role="tooltip"][hidden] { display: none; }
@media (forced-colors: active) {
[role="tooltip"] { color: CanvasText; background: Canvas; border-color: CanvasText; }
}
@media (prefers-reduced-motion: no-preference) {
[role="tooltip"] { transition: opacity 0.15s ease; }
}
内容要求
- 内容应为简短的短语或句子;描述触发器,不要引入无关信息
- 避免逐字重复触发器的无障碍名称
- 不要包含标题、列表、链接、按钮、字段或其他控件
- 使用通俗易懂的语言;触发器获得焦点时,保持动态描述稳定
- 如果内容需要组织结构或包含多个句子,请改用常驻帮助文本、
aria-details、展开控件或对话框 - 不要仅为附加工具提示而让普通正文可聚焦——额外的 Tab 停止点会增加键盘导航的难度
何时不应使用工具提示
- 控件标签本身已能清楚说明其用途
- 信息必须始终可读 → 使用常驻帮助文本
- 仅支持触摸的界面 → 使用帮助按钮/展开控件或常驻帮助文本
- 内容较长或有结构 → 使用弹出层、展开控件或对话框
- 内容包含交互元素(链接、按钮)→ 使用弹出层或对话框
测试
- 键盘: 使用 Tab/Shift+Tab 到达触发器,确认工具提示出现时焦点不会移动;确认焦点仍在触发器上时按
Escape可关闭工具提示;确认工具提示不存在 Tab 停止点;确认焦点指示器仍然可见 - 指针/放大: 将指针悬停在触发器上,将指针移至工具提示的每个部分并确认工具提示保持可见;确认在悬停和焦点都不再保持工具提示时,工具提示会关闭;使用屏幕放大功能进行测试
- 触摸: 确认所有操作无需先发现悬停内容即可使用;确认关键信息可见,或可通过明确的控件访问;测试屏幕阅读器手势,并确认无需长按
- 屏幕阅读器: 确认没有工具提示时,触发器的无障碍名称正确;工具提示文本作为描述公开;名称/描述不会不必要地重复;焦点不会移动;重复聚焦不会产生过时的描述。测试受支持的浏览器/辅助技术组合并记录版本——呈现方式各有不同,没有一种通用的播报方式
- 视觉/响应式: 200%/400% 缩放、窄视口、文本间距覆盖、强制颜色模式、减少动态效果、RTL 文本、视口边缘定位
- 自动化: 可在组件测试中捕获缺失/重复的 ID、无法解析的
aria-describedby引用、无效的 ARIA 值、工具提示内可聚焦的后代元素、对比度不足、隐藏的触发器,以及过时的打开状态工具提示——但无法证明悬停可用性、持续显示、定位或屏幕阅读器呈现效果。将手动测试纳入发布流程。
常见问题
| 问题 | 修正方法 |
|---|---|
| 仅在悬停时显示工具提示 | 键盘聚焦时也显示 |
| 指针离开触发元素时隐藏工具提示 | 指针位于触发元素或工具提示上时,保持其打开 |
| 即使焦点仍在,指针离开时也隐藏工具提示 | 分别跟踪指针和焦点状态 |
| 固定超时后关闭工具提示 | 在触发元素移除、用户关闭或工具提示失效前保持可见 |
| 将焦点移入工具提示 | 让焦点保持在触发元素上 |
在 role="tooltip" 中放置链接或按钮 | 使用披露控件、非模态对话框或其他弹出内容 |
将 aria-expanded/aria-haspopup 用于自动显示的工具提示 | 使用 aria-describedby 和 role="tooltip" |
依赖 title 作为控件标签或说明 | 提供可见标签和持续显示或由作者提供的帮助信息 |
覆盖现有的 aria-describedby ID | 追加并保留所有相关引用 |
| 仅将必要的帮助信息关联到禁用控件 | 让说明信息可见 |
完成标准检查清单
- 工具提示是正确的模式(参见上方的模式选择表)
- 无需打开工具提示即可看到必要信息
- 触发元素具有完整的无障碍名称,且不依赖工具提示
- 工具提示元素上有
role="tooltip",且具有唯一的id - 触发元素通过
aria-describedby引用该工具提示,且不会丢失其他描述 - 悬停和键盘聚焦时都会显示工具提示
- 按下
Escape可关闭工具提示且不移动焦点;不会在固定时间后关闭 - 工具提示可悬停(指针可移到其上而不会将其关闭)
- 工具提示及其所有后代均不可聚焦;内部没有交互式内容
- 触控用户可看到相关信息或使用明确的帮助控件
- 禁用控件不会隐藏其说明
- 文本对比度为 4.5:1;所需的非文本对比度为 3:1
- 内容可重排或换行,并能在缩放及覆盖文本间距时正常操作
- 动画遵循
prefers-reduced-motion设置 - 已在键盘、指针、触控、放大功能及受支持的屏幕阅读器环境下进行测试
关键 WCAG 标准
- 1.3.1 信息和关系(A)
- 1.4.3 对比度最低要求(AA)
- 1.4.10 重排(AA)
- 1.4.11 非文本对比度(AA)
- 1.4.12 文本间距(AA)
- 1.4.13 悬停或聚焦时的内容(AA)—— 仅在悬停时显示或无法关闭属于严重问题
- 2.1.1 键盘(A)—— 键盘无法触发工具提示属于严重问题
- 2.1.2 无键盘陷阱(A)
- 2.4.7 焦点可见(AA)
- 2.4.11 焦点未被遮挡(最低要求)(AA)
- 2.5.8 目标尺寸最低要求(AA)
- 4.1.2 名称、角色、值(A)
参考资料
- 完整最佳实践指南
- WCAG 2.2 理解 1.4.13 悬停或聚焦时的内容
- WAI-ARIA APG — 工具提示模式(W3C 标记为正在编写中——可作为实用指导,但不能替代用户测试)
- 技术 SCR39:可悬停、可关闭且持续显示
- 失败案例 F95:悬停时显示的内容无法悬停
标准展望: WCAG 3.0 正在制定中;预计 1.4.13 的要求 将继续保留。 关注:https://www.w3.org/TR/wcag-3.0/