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

mat-menu内嵌标题无法被JAWS/NVDA读取的无障碍适配问题咨询

解决Mat-Menu内嵌标题的屏幕阅读器无障碍问题

核心问题分析

你的代码中存在两个关键问题导致屏幕阅读器忽略标题:

  1. 手动给<ul>添加了role="menu",与Angular Material的mat-menu自动生成的role="menu"容器冲突,打乱了屏幕阅读器的语义识别逻辑
  2. 标题与菜单容器没有通过ARIA属性关联,屏幕阅读器无法将标题与菜单内容建立归属关系

解决方案1:单分组场景下关联标题与菜单容器

通过aria-labelledby将标题与mat-menu容器绑定,同时修正冗余的ARIA角色,确保JAWS/NVDA能正确识别并播报标题。

修改后的代码:

<button mat-button [matMenuTriggerFor]="A">Link list</button>
<mat-menu #A="matMenu" aria-labelledby="menu-heading">
  <h2 id="menu-heading" role="heading" aria-level="2">Heading</h2>
  <ul>
    <li mat-menu-item><a href="#">Link 1</a></li>
    <li mat-menu-item><a href="#">Link 2</a></li>
    <li mat-menu-item><a href="#">Link 3</a></li>
  </ul>
</mat-menu>

关键调整点:

  • 移除<ul>的role="menu",避免与mat-menu的内置角色冲突
  • 给标题设置唯一id,并让mat-menu通过aria-labelledby关联该id,明确菜单的标题归属
  • 给<h2>添加aria-level="2",明确标题层级,帮助屏幕阅读器理解内容结构

解决方案2:多分类场景下的分组标题处理

如果需要给菜单添加多个分类标题,可通过role="group"包裹每组菜单项,并关联对应标题,让屏幕阅读器在遍历菜单项时播报分组信息。

修改后的代码:

<button mat-button [matMenuTriggerFor]="A">Link list</button>
<mat-menu #A="matMenu">
  <h2 id="group1-heading" role="heading" aria-level="2">Group 1</h2>
  <div role="group" aria-labelledby="group1-heading">
    <li mat-menu-item><a href="#">Link 1</a></li>
    <li mat-menu-item><a href="#">Link 2</a></li>
  </div>
  
  <mat-divider></mat-divider>
  
  <h2 id="group2-heading" role="heading" aria-level="2">Group 2</h2>
  <div role="group" aria-labelledby="group2-heading">
    <li mat-menu-item><a href="#">Link 3</a></li>
    <li mat-menu-item><a href="#">Link 4</a></li>
  </div>
</mat-menu>

关键调整点:

  • 用role="group"包裹每组菜单项,并通过aria-labelledby关联对应分组标题
  • 加入mat-divider视觉区分分组,同时辅助屏幕阅读器识别分组边界

处理初始焦点导致的标题播报问题

由于mat-menu默认将焦点定位到第一个可交互菜单项,屏幕阅读器可能跳过标题播报。可通过菜单打开事件触发屏幕阅读器主动读取标题:

组件类代码:

import { ViewChild } from '@angular/core';
import { MatMenuTrigger } from '@angular/material/menu';

export class YourComponent {
  @ViewChild(MatMenuTrigger) menuTrigger!: MatMenuTrigger;

  onMenuOpened() {
    const heading = document.getElementById('menu-heading');
    if (heading) {
      // 临时添加aria-live属性,让屏幕阅读器礼貌播报标题
      heading.setAttribute('aria-live', 'polite');
      // 播报后移除属性,避免后续干扰
      setTimeout(() => heading.removeAttribute('aria-live'), 1000);
    }
  }
}

模板绑定事件:

<button mat-button [matMenuTriggerFor]="A" (menuOpened)="onMenuOpened()">Link list</button>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:21:09