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

使用NVDA屏幕阅读器时,ul中首个li标签无法通过向下箭头键导航的问题

可访问性问题修复方案:第一个列表项展开后NVDA无法用向下箭头读取内容

我帮你排查下这个问题,看起来第一个列表项展开后的内容没被NVDA正确识别到浏览流里,大概率是HTML语义结构不规范+焦点/ARIA属性处理不当导致的,咱们一步步来解决:

核心问题分析

你当前的代码把展开的内容<div>直接放在了<ul>下(作为<li>的同级元素),但根据HTML规范,<ul>的直接子元素只能是<li>,这种非法结构会让屏幕阅读器(尤其是对第一个列表项的语义校验更严格的NVDA)无法正确解析内容归属,这就是第一个项出问题、其他项能容错的关键原因。

另外还有两个次要问题:aria-expanded用了字符串值(标准应为布尔值),以及展开的内容容器不在焦点流里,导致阅读器无法主动捕获它。

具体修复步骤

1. 修正HTML语义结构,把展开内容放到<li>内部

把展开的内容容器移到对应列表项的<li>里面,确保<ul>的子元素只有<li>,恢复正确的列表语义:

<ul className="overview-menu" aria-label="菜单">
  {options.map((opt, i) => (
    <li 
      key={opt.name} 
      className={`overview-menu-option ${option?.name === opt.name ? 'active' : 'inactive'} ${contentBoxType}`}
    >
      <button 
        className={`overview-menu-option-btn ${option?.name === opt.name ? 'active' : 'inactive'} ${contentBoxType}`}
        aria-expanded={!!(option && option.name === opt.name)} {/* 改为布尔值,符合ARIA规范 */}
        onClick={() => getContents(opt)}
      >
        {opt.name}
        <ChevronIcon aria-hidden="true" /> {/* 图标设为装饰性,隐藏给屏幕阅读器 */}
      </button>
      
      {/* 把内容容器放到<li>内部,添加tabindex让它能被聚焦 */}
      {isOptionClick && option?.name === opt.name ? (
        <div 
          key={`${opt.name}-contents`} 
          className={`overview-menu-option-contents ${contentBoxType}`}
          tabindex="-1" {/* 允许聚焦但不进入Tab流,适配阅读器浏览模式 */}
          aria-label="展开的详情内容"
          data-name={opt.name} {/* 方便后续定位元素 */}
        >
          {option.contents}
        </div>
      ) : null}
    </li>
  ))}
</ul>

2. 优化焦点管理,确保展开后内容被阅读器捕获

在getContents函数里,添加焦点自动跳转逻辑,当内容展开后主动聚焦到内容容器,让NVDA能立刻识别到新内容:

const getContents = (opt) => {
  // 原有逻辑:更新选中项状态
  setOption(opt);
  setIsOptionClick(true);

  // 等待DOM更新后,聚焦到展开的内容容器
  setTimeout(() => {
    const contentEl = document.querySelector(`.overview-menu-option-contents[data-name="${opt.name}"]`);
    if (contentEl) {
      contentEl.focus();
    }
  }, 0);
};

如果用React的useEffect会更优雅,避免定时器:

import { useEffect } from 'react';

useEffect(() => {
  if (isOptionClick && option) {
    const contentEl = document.querySelector(`.overview-menu-option-contents[data-name="${option.name}"]`);
    if (contentEl) {
      contentEl.focus();
    }
  }
}, [isOptionClick, option]);

3. 验证ARIA属性规范

把aria-expanded从字符串"true"/"false"改成布尔值true/false,虽然部分浏览器兼容字符串,但严格遵循WAI-ARIA规范能避免潜在的阅读器解析问题。

测试验证

修复后用NVDA测试:

  1. 按Tab键导航到第一个列表项的按钮,NVDA会提示按钮状态和文本
  2. 按下Enter展开内容,焦点会自动跳转到内容容器
  3. 按向下箭头键,NVDA会正常读取展开的内容文本

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 19:18:09