如何让屏幕阅读器读取非聚焦的selected类元素内容?
解决方案:利用
aria-activedescendant实现屏幕阅读器读取选中项 这个需求完全可以实现!你遇到的问题核心是没用到ARIA里专门处理「聚焦容器+活跃子项」场景的属性——aria-activedescendant,这正是解决这类键盘导航+屏幕阅读器适配的标准方案。
核心思路
当父容器(你的div[tabindex="0"])获得焦点时,通过aria-activedescendant属性关联当前选中的li元素,屏幕阅读器会自动读取这个关联元素的内容,无需让每个li单独获得焦点。
具体实现步骤
- 给每个可选中的
li添加唯一id:这样才能通过aria-activedescendant精准关联到目标元素。 - 在聚焦的父
div上初始化aria-activedescendant:默认指向初始选中的li的id。 - 监听方向键事件,动态更新选中状态和
aria-activedescendant:切换selected类的同时,同步更新父容器的aria-activedescendant值。 - 确保语义正确:原生
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
相关产品推荐
相关产品推荐

