Screen Reader Testing

作者 wshobson46891e7e60da无许可证收录于 2026年10月8日更新于 2026年10月8日

Test web applications with screen readers including VoiceOver, NVDA, and JAWS. Use when validating screen reader compatibility, debugging accessibility issues, or ensuring assistive technology support.

AI 生成的概览

指导使用 VoiceOver、NVDA、JAWS 和 TalkBack 等屏幕阅读器测试网页应用。

功能
提供使用屏幕阅读器验证网页无障碍的实用参考,涵盖主要屏幕阅读器与浏览器的组合、测试优先级以及键盘命令。它包含针对导航、表单、动态内容、表格和模态框的检查清单与测试脚本,并给出常见组件的 ARIA 与焦点管理代码示例。此外还列出常见无障碍问题及其修复方法和调试技巧。
适用场景
适用于验证屏幕阅读器兼容性、测试 ARIA 实现、调试辅助技术问题,或检查表单、导航和动态内容的无障碍性。
运行要求
不附带脚本或工具,仅为纯说明性参考。实际测试需要相应的屏幕阅读器和平台,例如 macOS 或 iOS 上的 VoiceOver、Windows 上的 NVDA 或 JAWS,以及 Android 上的 TalkBack。

Screen Reader Testing

Practical guide to testing web applications with screen readers for comprehensive accessibility validation.

When to Use This Skill

  • Validating screen reader compatibility
  • Testing ARIA implementations
  • Debugging assistive technology issues
  • Verifying form accessibility
  • Testing dynamic content announcements
  • Ensuring navigation accessibility

Core Concepts

1. Major Screen Readers

Screen ReaderPlatformBrowserUsage
VoiceOvermacOS/iOSSafari~15%
NVDAWindowsFirefox/Chrome~31%
JAWSWindowsChrome/IE~40%
TalkBackAndroidChrome~10%
NarratorWindowsEdge~4%

2. Testing Priority

Minimum Coverage:1. NVDA + Firefox (Windows)2. VoiceOver + Safari (macOS)3. VoiceOver + Safari (iOS)
Comprehensive Coverage:+ JAWS + Chrome (Windows)+ TalkBack + Chrome (Android)+ Narrator + Edge (Windows)

3. Screen Reader Modes

ModePurposeWhen Used
Browse/VirtualRead contentDefault reading
Focus/FormsInteract with controlsFilling forms
ApplicationCustom widgetsARIA applications

VoiceOver (macOS)

Setup

Enable: System Preferences → Accessibility → VoiceOverToggle: Cmd + F5Quick Toggle: Triple-press Touch ID

Essential Commands

Navigation:VO = Ctrl + Option (VoiceOver modifier)
VO + Right Arrow   Next elementVO + Left Arrow    Previous elementVO + Shift + Down  Enter groupVO + Shift + Up    Exit group
Reading:VO + A             Read all from cursorCtrl               Stop speakingVO + B             Read current paragraph
Interaction:VO + Space         Activate elementVO + Shift + M     Open menuTab                Next focusable elementShift + Tab        Previous focusable element
Rotor (VO + U):Navigate by: Headings, Links, Forms, LandmarksLeft/Right Arrow   Change rotor categoryUp/Down Arrow      Navigate within categoryEnter              Go to item
Web Specific:VO + Cmd + H       Next headingVO + Cmd + J       Next form controlVO + Cmd + L       Next linkVO + Cmd + T       Next table

Testing Checklist

markdown
## VoiceOver Testing Checklist
### Page Load
- [ ] Page title announced- [ ] Main landmark found- [ ] Skip link works
### Navigation
- [ ] All headings discoverable via rotor- [ ] Heading levels logical (H1 → H2 → H3)- [ ] Landmarks properly labeled- [ ] Skip links functional
### Links & Buttons
- [ ] Link purpose clear- [ ] Button actions described- [ ] New window/tab announced
### Forms
- [ ] All labels read with inputs- [ ] Required fields announced- [ ] Error messages read- [ ] Instructions available- [ ] Focus moves to errors
### Dynamic Content
- [ ] Alerts announced immediately- [ ] Loading states communicated- [ ] Content updates announced- [ ] Modals trap focus correctly
### Tables
- [ ] Headers associated with cells- [ ] Table navigation works- [ ] Complex tables have captions

Common Issues & Fixes

html
<!-- Issue: Button not announcing purpose --><button><svg>...</svg></button>
<!-- Fix --><button aria-label="Close dialog"><svg aria-hidden="true">...</svg></button>
<!-- Issue: Dynamic content not announced --><div id="results">New results loaded</div>
<!-- Fix --><div id="results" role="status" aria-live="polite">New results loaded</div>
<!-- Issue: Form error not read --><input type="email" /><span class="error">Invalid email</span>
<!-- Fix --><input type="email" aria-invalid="true" aria-describedby="email-error" /><span id="email-error" role="alert">Invalid email</span>

NVDA (Windows)

Setup

Download: nvaccess.orgStart: Ctrl + Alt + NStop: Insert + Q

Essential Commands

Navigation:Insert = NVDA modifier
Down Arrow         Next lineUp Arrow           Previous lineTab                Next focusableShift + Tab        Previous focusable
Reading:NVDA + Down Arrow  Say allCtrl               Stop speechNVDA + Up Arrow    Current line
Headings:H                  Next headingShift + H          Previous heading1-6                Heading level 1-6
Forms:F                  Next form fieldB                  Next buttonE                  Next edit fieldX                  Next checkboxC                  Next combo box
Links:K                  Next linkU                  Next unvisited linkV                  Next visited link
Landmarks:D                  Next landmarkShift + D          Previous landmark
Tables:T                  Next tableCtrl + Alt + Arrows Navigate cells
Elements List (NVDA + F7):Shows all links, headings, form fields, landmarks

Browse vs Focus Mode

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

Testing Script

markdown
## NVDA Test Script
### Initial Load
1. Navigate to page2. Let page finish loading3. Press Insert + Down to read all4. Note: Page title, main content identified?
### Landmark Navigation
1. Press D repeatedly2. Check: All main areas reachable?3. Check: Landmarks properly labeled?
### Heading Navigation
1. Press Insert + F7 → Headings2. Check: Logical heading structure?3. Press H to navigate headings4. Check: All sections discoverable?
### Form Testing
1. Press F to find first form field2. Check: Label read?3. Fill in invalid data4. Submit form5. Check: Errors announced?6. Check: Focus moved to error?
### Interactive Elements
1. Tab through all interactive elements2. Check: Each announces role and state3. Activate buttons with Enter/Space4. Check: Result announced?
### Dynamic Content
1. Trigger content update2. Check: Change announced?3. Open modal4. Check: Focus trapped?5. Close modal6. Check: Focus returns?

JAWS (Windows)

Essential Commands

Start: Desktop shortcut or Ctrl + Alt + JVirtual Cursor: Auto-enabled in browsers
Navigation:Arrow keys         Navigate contentTab                Next focusableInsert + Down      Read allCtrl               Stop speech
Quick Keys:H                  Next headingT                  Next tableF                  Next form fieldB                  Next buttonG                  Next graphicL                  Next list;                  Next landmark
Forms Mode:Enter              Enter forms modeNumpad +           Exit forms modeF5                 List form fields
Lists:Insert + F7        Link listInsert + F6        Heading listInsert + F5        Form field list
Tables:Ctrl + Alt + Arrows Table navigation

TalkBack (Android)

Setup

Enable: Settings → Accessibility → TalkBackToggle: Hold both volume buttons 3 seconds

Gestures

Explore: Drag finger across screenNext: Swipe rightPrevious: Swipe leftActivate: Double tapScroll: Two finger swipe
Reading Controls (swipe up then right):- Headings- Links- Controls- Characters- Words- Lines- Paragraphs

Common Test Scenarios

1. Modal Dialog

html
<!-- Accessible modal structure --><div  role="dialog"  aria-modal="true"  aria-labelledby="dialog-title"  aria-describedby="dialog-desc">  <h2 id="dialog-title">Confirm Delete</h2>  <p id="dialog-desc">This action cannot be undone.</p>  <button>Cancel</button>  <button>Delete</button></div>
javascript
// Focus managementfunction 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);  }}

2. Live Regions

html
<!-- Status messages (polite) --><div role="status" aria-live="polite" aria-atomic="true">  <!-- Content updates will be announced after current speech --></div>
<!-- Alerts (assertive) --><div role="alert" aria-live="assertive">  <!-- Content updates interrupt current speech --></div>
<!-- Progress updates --><div  role="progressbar"  aria-valuenow="75"  aria-valuemin="0"  aria-valuemax="100"  aria-label="Upload progress"></div>
<!-- Log (additions only) --><div role="log" aria-live="polite" aria-relevant="additions">  <!-- New messages announced, removals not --></div>

3. Tab Interface

html
<div role="tablist" aria-label="Product information">  <button role="tab" id="tab-1" aria-selected="true" aria-controls="panel-1">    Description  </button>  <button    role="tab"    id="tab-2"    aria-selected="false"    aria-controls="panel-2"    tabindex="-1"  >    Reviews  </button></div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">  Product description content...</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>  Reviews content...</div>
javascript
// Tab keyboard navigationtablist.addEventListener("keydown", (e) => {  const tabs = [...tablist.querySelectorAll('[role="tab"]')];  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();});

Debugging Tips

javascript
// Log what screen reader seesfunction 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",  });}

Best Practices

Do's

  • Test with actual screen readers - Not just simulators
  • Use semantic HTML first - ARIA is supplemental
  • Test in browse and focus modes - Different experiences
  • Verify focus management - Especially for SPAs
  • Test keyboard only first - Foundation for SR testing

Don'ts

  • Don't assume one SR is enough - Test multiple
  • Don't ignore mobile - Growing user base
  • Don't test only happy path - Test error states
  • Don't skip dynamic content - Most common issues
  • Don't rely on visual testing - Different experience

来源与署名

来源:wshobson/agents位于plugins/accessibility-compliance/skills/screen-reader-testing提交46891e7

许可证: 无许可证

内容归原作者所有。SourceWeft 从公开仓库中收录这些内容。

举报或申请下架