You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VoiceOver中role="option"的aria-selected状态异常播报及null问题

自定义Listbox在VoiceOver下的可访问性问题修复

问题说明

用role="listbox"和role="option"实现自定义列表框时,VoiceOver会出现两个异常:

  • 首次选中选项会播报选中状态,但切换到其他选项时,不会播报状态变更
  • 导航选项时,会额外弹出You are on a selectable (null), inside a listbox的错误提示,其中“null”属于无效播报

原始代码

<div role="listbox" aria-label="Options">
  <div role="option" aria-selected="true" tabindex="0">Option 1</div>
  <div role="option" aria-selected="false" tabindex="-1">Option 2</div>
  <div role="option" aria-selected="false" tabindex="-1">Option 3</div>
</div>

修复办法

1. 解决切换选项无状态播报的问题

VoiceOver需要明确的状态变更触发信号,仅修改aria-selected属性不足以让它感知到变化。正确的做法是:切换选中项时,将旧选中项的tabindex设为-1,新选中项设为0并主动聚焦,确保辅助技术能捕捉到焦点和状态的双重变化。

2. 消除“selectable (null)”错误播报

这个问题是因为VoiceOver对纯div模拟的option语义识别出现混淆。只需给父容器listbox添加aria-multiselectable="false",明确这是单选列表框,就能解决“null”的错误播报。

修复后的完整代码

HTML部分

<div role="listbox" aria-label="Options" aria-multiselectable="false">
  <div role="option" aria-selected="true" tabindex="0">Option 1</div>
  <div role="option" aria-selected="false" tabindex="-1">Option 2</div>
  <div role="option" aria-selected="false" tabindex="-1">Option 3</div>
</div>

JavaScript交互逻辑(必加)

要实现完整的键盘导航和状态切换,需补充以下代码:

const listbox = document.querySelector('[role="listbox"]');
const options = Array.from(listbox.querySelectorAll('[role="option"]'));

// 为每个选项绑定点击和键盘事件
options.forEach(option => {
  option.addEventListener('click', () => setSelectedOption(option));
  
  option.addEventListener('keydown', (e) => {
    switch(e.key) {
      case 'Enter':
      case ' ':
        e.preventDefault();
        setSelectedOption(option);
        break;
      case 'ArrowDown':
        e.preventDefault();
        const nextOption = options[(options.indexOf(option) + 1) % options.length];
        setSelectedOption(nextOption);
        break;
      case 'ArrowUp':
        e.preventDefault();
        const prevOption = options[(options.indexOf(option) - 1 + options.length) % options.length];
        setSelectedOption(prevOption);
        break;
      // 可选:支持Home/End键快速跳转
      case 'Home':
        e.preventDefault();
        setSelectedOption(options[0]);
        break;
      case 'End':
        e.preventDefault();
        setSelectedOption(options[options.length - 1]);
        break;
    }
  });
});

// 选中选项的核心函数
function setSelectedOption(target) {
  // 重置所有选项的选中状态和焦点
  options.forEach(opt => {
    opt.setAttribute('aria-selected', 'false');
    opt.setAttribute('tabindex', '-1');
  });
  
  // 设置目标选项为选中状态并聚焦
  target.setAttribute('aria-selected', 'true');
  target.setAttribute('tabindex', '0');
  target.focus();
}

额外优化建议

  • 可选添加aria-live="polite"区域,当选中状态变更时,自定义播报内容(比如“已选中Option 2”),进一步提升体验
  • 确保所有交互符合WAI-ARIA列表框规范,让键盘操作和屏幕阅读器体验与原生控件一致

内容的提问来源于stack exchange,提问作者Muthu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:24:52