VoiceOver Testing Checklist

VoiceOver Testing Checklist VoiceOver Testing Checklist【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agentsPage LoadPage title announcedMain landmark foundSkip link worksNavigationAll headings discoverable via rotorHeading levels logical (H1 → H2 → H3)Landmarks properly labeledSkip links functionalLinks ButtonsLink purpose clearButton actions describedNew window/tab announcedFormsAll labels read with inputsRequired fields announcedError messages readInstructions availableFocus moves to errorsDynamic ContentAlerts announced immediatelyLoading states communicatedContent updates announcedModals trap focus correctlyTablesHeaders associated with cellsTable navigation worksComplex tables have captions### 常见问题与修复 技能文档给出了三组典型“问题代码 → 修复代码”对照 html !-- Issue: Button not announcing purpose -- buttonsvg.../svg/button !-- Fix -- button aria-labelClose dialogsvg aria-hiddentrue.../svg/button !-- Issue: Dynamic content not announced -- div idresultsNew results loaded/div !-- Fix -- div idresults rolestatus aria-livepoliteNew results loaded/div !-- Issue: Form error not read -- input typeemail / span classerrorInvalid email/span !-- Fix -- input typeemail aria-invalidtrue aria-describedbyemail-error / span idemail-error rolealertInvalid email/span三处修复分别对应屏幕阅读器领域的三类经典缺陷图标按钮无名称纯 SVG 的button没有可访问名称屏幕阅读器只会播报 “button”。修复方式为按钮加aria-label声明用途同时给 SVG 加aria-hiddentrue防止其内部文本被重复播报。动态内容静默更新JS 直接改写div内容不会触发播报需将该区域标记为rolestatus等价于aria-livepolite的隐式声明或显式加aria-live。表单错误不播报错误提示须通过aria-describedby与输入控件关联使播报名称中包含错误用aria-invalidtrue标记无效状态并给提示元素rolealert使其作为断言型实时区域即时播报。NVDAWindows完整测试手册环境配置Download: nvaccess.org Start: Ctrl Alt N Stop: Insert Q常用命令全集NVDA 修饰键为Insert常用命令如下Navigation: Insert NVDA modifier Down Arrow Next line Up Arrow Previous line Tab Next focusable Shift Tab Previous focusable Reading: NVDA Down Arrow Say all Ctrl Stop speech NVDA Up Arrow Current line Headings: H Next heading Shift H Previous heading 1-6 Heading level 1-6 Forms: F Next form field B Next button E Next edit field X Next checkbox C Next combo box Links: K Next link U Next unvisited link V Next visited link Landmarks: D Next landmark Shift D Previous landmark Tables: T Next table Ctrl Alt Arrows Navigate cells Elements List (NVDA F7): Shows all links, headings, form fields, landmarks几个值得注意的命令NVDA F7打开元素列表Elements List可一次性列出页面全部链接、标题、表单字段、地标适合快速核对页面结构Ctrl Alt 方向键用于表格单元格间导航是检验表头关联是否正确的直接手段。Browse 模式与 Focus 模式NVDA 会在两种模式间自动切换这是 Windows 侧测试必须观察的行为NVDA automatically switches modes: - Browse Mode: Arrow keys navigate content - Focus Mode: Arrow keys control interactive elements Manual switch: NVDA Space Watch for: - Browse mode announcement when navigating - Focus mode when entering form fields - Application role forces forms mode排查“方向键行为突然变了”这类问题先确认播报里出现的是 “Browse mode” 还是 “Focus mode”特别地roleapplication会强制进入表单模式这在自绘 Canvas/富文本组件中影响很大。NVDA 测试脚本技能文档提供了一套按步骤执行的 NVDA 测试脚本从初始加载到动态内容共六个环节## NVDA Test Script ### Initial Load 1. Navigate to page 2. Let page finish loading 3. Press Insert Down to read all 4. Note: Page title, main content identified? ### Landmark Navigation 1. Press D repeatedly 2. Check: All main areas reachable? 3. Check: Landmarks properly labeled? ### Heading Navigation 1. Press Insert F7 → Headings 2. Check: Logical heading structure? 3. Press H to navigate headings 4. Check: All sections discoverable? ### Form Testing 1. Press F to find first form field 2. Check: Label read? 3. Fill in invalid data 4. Submit form 5. Check: Errors announced? 6. Check: Focus moved to error? ### Interactive Elements 1. Tab through all interactive elements 2. Check: Each announces role and state 3. Activate buttons with Enter/Space 4. Check: Result announced? ### Dynamic Content 1. Trigger content update 2. Check: Change announced? 3. Open modal 4. Check: Focus trapped? 5. Close modal 6. Check: Focus returns?该脚本的验证顺序暗含一条依赖链地标 → 标题 → 表单 → 交互元素 → 动态内容前一级通过是后一级有效测试的前提例如标题结构混乱时Insert F7的结果就不可信。JAWSWindows与 TalkBackAndroid要点JAWS 常用命令Start: Desktop shortcut or Ctrl Alt J Virtual Cursor: Auto-enabled in browsers Navigation: Arrow keys Navigate content Tab Next focusable Insert Down Read all Ctrl Stop speech Quick Keys: H Next heading T Next table F Next form field B Next button G Next graphic L Next list ; Next landmark Forms Mode: Enter Enter forms mode Numpad Exit forms mode F5 List form fields Lists: Insert F7 Link list Insert F6 Heading list Insert F5 Form field list Tables: Ctrl Alt Arrows Table navigationJAWS 在浏览器中默认启用虚拟光标Virtual Cursor其“元素列表”三件套Insert F7链接列表、Insert F6标题列表、Insert F5表单字段列表与 NVDA 的元素列表功能对应是两份环境共用的结构核对手段。TalkBackAndroidEnable: Settings → Accessibility → TalkBack Toggle: Hold both volume buttons 3 seconds移动端全部依赖手势完成Explore: Drag finger across screen Next: Swipe right Previous: Swipe left Activate: Double tap Scroll: Two finger swipe Reading Controls (swipe up then right): - Headings - Links - Controls - Characters - Words - Lines - ParagraphsTalkBack 的 “Reading Controls”上滑再右滑唤出提供按标题/链接/控件等粒度的导航其作用等价于 VoiceOver 的 Rotor 和 NVDA/JAWS 的元素列表——移动端测试时应确认页面在按标题导航时呈现的层级与桌面端一致。三大典型场景的参考实现以下三组“HTML JavaScript”参考实现均出自技能文档是屏幕阅读器验证中最常出问题的三个组件类型。场景 1模态对话框Modal Dialog模态框必须满足三件事角色与标题关联roledialogaria-modaltruearia-labelledby、焦点被约束在框内focus trap、关闭后焦点归还触发元素。!-- Accessible modal structure -- div roledialog aria-modaltrue aria-labelledbydialog-title aria-describedbydialog-desc h2 iddialog-titleConfirm Delete/h2 p iddialog-descThis action cannot be undone./p buttonCancel/button buttonDelete/button /div// Focus management function openModal(modal) { // Store last focused element lastFocus document.activeElement; // Move focus to modal modal.querySelector(h2).focus(); // Trap focus modal.addEventListener(keydown, trapFocus); } function closeModal(modal) { // Return focus lastFocus.focus(); } function trapFocus(e) { if (e.key Tab) { const focusable modal.querySelectorAll( button, [href], input, select, textarea, [tabindex]:not([tabindex-1]), ); const first focusable[0]; const last focusable[focusable.length - 1]; if (e.shiftKey document.activeElement first) { last.focus(); e.preventDefault(); } else if (!e.shiftKey document.activeElement last) { first.focus(); e.preventDefault(); } } if (e.key Escape) { closeModal(modal); } }用屏幕阅读器验证时对应检查点打开后 NVDA 是否播报对话框标题VoiceOver 会播报 “Confirm Delete, dialog”、Tab 循环是否困在框内、关闭后焦点是否回到触发按钮——这正是 NVDA 测试脚本 “Dynamic Content” 环节的 36 步。场景 2实时区域Live Regions动态内容的播报策略由aria-live的礼貌等级与角色决定!-- Status messages (polite) -- div rolestatus aria-livepolite aria-atomictrue !-- Content updates will be announced after current speech -- /div !-- Alerts (assertive) -- div rolealert aria-liveassertive !-- Content updates interrupt current speech -- /div !-- Progress updates -- div roleprogressbar aria-valuenow75 aria-valuemin0 aria-valuemax100 aria-labelUpload progress /div !-- Log (additions only) -- div rolelog aria-livepolite aria-relevantadditions !-- New messages announced, removals not -- /div选择原则rolestatuspolite用于“结果已加载”这类常规状态更新不打断当前播报rolealertassertive用于表单校验失败、系统错误这类必须立刻感知的事件rolelog配合aria-relevantadditions只播报追加内容适合消息流、通知面板进度类内容用roleprogressbar并维护aria-valuenow。场景 3标签页界面Tab Interface标签页需要完整的tablist / tab / tabpanel角色链配合aria-selected、aria-controls、tabindex管理并实现方向键 / Home / End 键盘导航div roletablist aria-labelProduct information button roletab idtab-1 aria-selectedtrue aria-controlspanel-1 Description /button button roletab idtab-2 aria-selectedfalse aria-controlspanel-2 tabindex-1 Reviews /button /div div roletabpanel idpanel-1 aria-labelledbytab-1 Product description content... /div div roletabpanel idpanel-2 aria-labelledbytab-2 hidden Reviews content... /div// Tab keyboard navigation tablist.addEventListener(keydown, (e) { const tabs [...tablist.querySelectorAll([roletab])]; const index tabs.indexOf(document.activeElement); let newIndex; switch (e.key) { case ArrowRight: newIndex (index 1) % tabs.length; break; case ArrowLeft: newIndex (index - 1 tabs.length) % tabs.length; break; case Home: newIndex 0; break; case End: newIndex tabs.length - 1; break; default: return; } tabs[newIndex].focus(); activateTab(tabs[newIndex]); e.preventDefault(); });实现要点非选中的 tab 使用tabindex-1使 Tab 键只进出 tablist 一次、方向键在内部切换roving tabindex 模式隐藏的 panel 用hidden属性从可访问性树中移除避免屏幕阅读器读到已隐藏内容。用 NVDA 验证时焦点停在 tab 上应听到 “Tab, 2 of 2, Description, unselected” 之类的角色、序号与状态播报。调试技巧查看屏幕阅读器“看到”的内容当播报不符合预期时技能文档提供了一个控制台辅助函数用于打印元素的等效角色、可访问名称与状态帮助对齐 DOM 与屏幕阅读器认知// Log what screen reader sees function logAccessibleName(element) { const computed window.getComputedStyle(element); console.log({ role: element.getAttribute(role) || element.tagName, name: element.getAttribute(aria-label) || element.getAttribute(aria-labelledby) || element.textContent, state: { expanded: element.getAttribute(aria-expanded), selected: element.getAttribute(aria-selected), checked: element.getAttribute(aria-checked), disabled: element.disabled, }, visible: computed.display ! none computed.visibility ! hidden, }); }【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考