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

如何让屏幕阅读器读取非聚焦的selected类元素内容?

解决方案:利用aria-activedescendant实现屏幕阅读器读取选中项

这个需求完全可以实现!你遇到的问题核心是没用到ARIA里专门处理「聚焦容器+活跃子项」场景的属性——aria-activedescendant,这正是解决这类键盘导航+屏幕阅读器适配的标准方案。

核心思路

当父容器(你的div[tabindex="0"])获得焦点时,通过aria-activedescendant属性关联当前选中的li元素,屏幕阅读器会自动读取这个关联元素的内容,无需让每个li单独获得焦点。

具体实现步骤

  1. 给每个可选中的li添加唯一id:这样才能通过aria-activedescendant精准关联到目标元素。
  2. 在聚焦的父div上初始化aria-activedescendant:默认指向初始选中的li的id。
  3. 监听方向键事件,动态更新选中状态和aria-activedescendant:切换selected类的同时,同步更新父容器的aria-activedescendant值。
  4. 确保语义正确:原生ul和li不需要额外添加role="list"/role="listitem"(浏览器默认已经识别),如果是自定义结构才需要补充。

修改后的完整示例代码

HTML

<div tabindex="0" class="focus-container" aria-activedescendant="item1-1">
  <span>title1</span>
  <ul>
    <li id="item1-1" class="selected">item1</li>
    <li id="item1-2">item2</li>
    <li id="item1-3">item3</li>
  </ul>
</div>
<div tabindex="0" class="focus-container">
  <span>title2</span>
  <ul>
    <li id="item2-1">item1</li>
    <li id="item2-2">item2</li>
    <li id="item2-3">item3</li>
  </ul>
</div>

CSS

.focus-container {
  padding: 8px;
  border: 1px solid #ccc;
  margin: 10px 0;
}
.focus-container:focus {
  outline: 2px solid #005fcc;
}
.selected {
  background-color: #e6f2ff;
  font-weight: bold;
}

JavaScript

const containers = document.querySelectorAll('.focus-container');

containers.forEach(container => {
  const items = container.querySelectorAll('li');
  let currentIndex = Array.from(items).findIndex(item => item.classList.contains('selected'));
  // 如果初始没有选中项,默认选中第一个
  if (currentIndex === -1) {
    currentIndex = 0;
    items[currentIndex].classList.add('selected');
    container.setAttribute('aria-activedescendant', items[currentIndex].id);
  }

  container.addEventListener('keydown', (e) => {
    e.preventDefault();
    const totalItems = items.length;

    // 处理上箭头
    if (e.key === 'ArrowUp') {
      currentIndex = currentIndex > 0 ? currentIndex - 1 : totalItems - 1;
    }
    // 处理下箭头
    else if (e.key === 'ArrowDown') {
      currentIndex = currentIndex < totalItems - 1 ? currentIndex + 1 : 0;
    }
    // 可选:处理回车/空格触发选中逻辑
    else if (e.key === 'Enter' || e.key === ' ') {
      console.log('选中了:', items[currentIndex].textContent);
      return;
    }

    // 更新选中状态和aria属性
    items.forEach(item => item.classList.remove('selected'));
    items[currentIndex].classList.add('selected');
    container.setAttribute('aria-activedescendant', items[currentIndex].id);
  });
});

关键说明

  • aria-activedescendant的作用:它告诉屏幕阅读器,当前聚焦的容器元素的“活跃交互项”是哪个子元素,阅读器会自动读取该子元素的文本内容,无需让子元素获得焦点。
  • 为什么之前的方法无效:aria-label是给聚焦元素本身设置描述,无法动态关联子项;原生ul/li本身就有正确的语义,额外加role不会改变阅读器的处理逻辑,而缺少的正是关联活跃子项的机制。
  • 兼容性:这个属性在所有主流屏幕阅读器(NVDA、VoiceOver、JAWS)和浏览器中都有很好的支持,是WCAG标准推荐的实现方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:02:35