mcpField
T
tooltips

tooltips

github.com/mgifford设计与 UI57150 次安装6 周前更新
代码仓库

关于 tooltips

面向包含 Tooltip 的界面开发与审查,这项无障碍技能提供选择合适交互模式、实现规范和测试方法。重点涵盖键盘、触控、辅助技术及 WCAG 要求。

主要功能

  1. 01判断 Tooltip 是否适用
  2. 02键盘与指针交互规则
  3. 03ARIA 关联与语义要求
  4. 04触控和视觉设计建议
  5. 05无障碍测试清单

适用场景

  1. 01审查组件的键盘可达性
  2. 02检查 Tooltip 的 ARIA 标记
  3. 03评估触控及放大镜访问
  4. 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 3.0 正在制定中;预计 1.4.13 的要求 将继续保留。 关注:https://www.w3.org/TR/wcag-3.0/

评论

支持 Markdown