NVDA屏幕阅读器无障碍问题:切换锚点时读取双标签
NVDA无障碍阅读器切换锚点标签时重复读取内容的问题
问题现象
使用NVDA无障碍屏幕阅读器切换锚点标签(Knowledge和Support)时,会同时读出两个标签内容。比如从激活的Knowledge切换到Support,或反向切换时,本该只读取当前切换到的标签,实际却两个都读。但用Tab/Shift+Tab切换时读取正常。已尝试更换Chrome扩展阅读器、添加TabIndex、使用aria-labelledby属性等方案,问题仍未解决。
问题代码分析
当前代码逻辑存在冗余:针对每个scope状态(Knowledge/Support)都渲染了两组锚点标签,导致切换时DOM元素的替换可能触发NVDA的重复读取。比如当scope为Knowledge时,页面上同时存在激活状态的Knowledge锚点和未激活的Support锚点;切换到Support时,原有的两个锚点被替换成另外两个,NVDA可能在DOM更新过程中捕捉到了多个元素的变化。
原代码片段:
<div class="my-toggle-bar"> <a *ngIf="mode == 'inbox' && scope == 'Knowledge'" aria-label="Knowledge filter button active" href="javascript:void(0)" (click)="changeScope('Knowledge')" [ngClass]="{'active': scope == 'Knowledge'}" class="active"> <span>Knowledge</span> </a> <a *ngIf="mode == 'inbox' && scope == 'Support'" aria-label="Knowledge filter button" href="javascript:void(0)" (click)="changeScope('Knowledge')" [ngClass]="{'active': scope == 'Knowledge'}" class="active"> <span>Knowledge</span> </a> <a *ngIf="mode == 'inbox' && scope == 'Knowledge'" aria-label="Support filter button" href="javascript:void(0)" [ngClass]="{'active': scope == 'Support'}" (click)="changeScope('Support')"> <span>Support</span> </a> <a *ngIf="mode == 'inbox' && scope == 'Support'" aria-label="Support filter button active" href="javascript:void(0)" [ngClass]="{'active': scope == 'Support'}" (click)="changeScope('Support')"> <span>Support</span> </a> </div>
解决方案
简化DOM结构,只保留两个锚点标签,通过动态绑定控制激活状态和aria-label,避免切换时DOM元素的频繁替换:
<div class="my-toggle-bar"> <a *ngIf="mode == 'inbox'" [aria-label]="scope == 'Knowledge' ? 'Knowledge filter button active' : 'Knowledge filter button'" href="javascript:void(0)" (click)="changeScope('Knowledge')" [ngClass]="{'active': scope == 'Knowledge'}"> <span>Knowledge</span> </a> <a *ngIf="mode == 'inbox'" [aria-label]="scope == 'Support' ? 'Support filter button active' : 'Support filter button'" href="javascript:void(0)" (click)="changeScope('Support')" [ngClass]="{'active': scope == 'Support'}"> <span>Support</span> </a> </div>
优化说明
- 移除冗余的
*ngIf判断,每个标签只保留一个实例,通过动态绑定控制状态 - 用
[aria-label]根据当前scope动态设置标签文本,替代原有的多个静态aria-label - 激活状态通过
[ngClass]动态切换,无需重复渲染相同元素 - 减少DOM更新频次,避免NVDA在元素替换时读取到多个内容
额外建议
- 避免使用
javascript:void(0),可以将<a>改为<button>元素,更符合按钮交互的语义,无障碍支持更好 - 如果必须使用
<a>,确保添加role="button"属性,明确交互类型
内容的提问来源于stack exchange,提问作者ZZZ
相关产品推荐
相关产品推荐

