mat-menu内嵌标题无法被JAWS/NVDA读取的无障碍适配问题咨询
核心问题分析
你的代码中存在两个关键问题导致屏幕阅读器忽略标题:
- 手动给
<ul>添加了role="menu",与Angular Material的mat-menu自动生成的role="menu"容器冲突,打乱了屏幕阅读器的语义识别逻辑 - 标题与菜单容器没有通过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
相关产品推荐
相关产品推荐

