下面是一个用Angular编写的下拉菜单示例,其中我使用HTML5 hidden
属性(换句话说,display: none;
)来显示/隐藏项目列表:
<button
id="my-btn
type="button"
aria-haspopup="menu"
aria-controls="my-menu"
[attr.aria-expanded]="isMenuOpen"
(click)="isMenuOpen = !isMenuOpen"
>
Menu
</button>
<ul
id="my-menu"
role="menu"
aria-labelledby="my-btn"
[hidden]="!isMenuOpen"
>
...
</ul>
在下一个示例中,我使用结构指令*ngIf
而不是属性hidden
来有条件地呈现列表。换句话说,每次isMenuOpen
更改时,列表现在都会添加到DOM中并从中删除。
<ul
id="my-menu"
role="menu"
aria-labelledby="my-btn"
*ngIf="isMenuOpen"
>
...
</ul>
忽略任何框架或性能问题,这两种实现与可访问性的观点有什么不同?
相当多的ARIA属性通过引用其他元素的ID(例如aria-controls
,aria-labelledby
等)来工作。从DOM中删除由这样的属性引用的元素比隐藏该元素更难以访问吗?
是,有一点不同。考虑这个简单的例子:
<button aria-labelledby="foo"></button>
尚未在页面上存在“foo”元素的地方。如果您通过https://validator.w3.org/nu等验证程序运行此代码,则会失败。
Error: The aria-labelledby attribute must point to an element in the same document.
从WCAG的角度来看,它会失败4.1.1 - Parsing。
此外,WCAG 4.1.2 - Name, Role, Value将是一个问题。按钮(在我的示例中)没有可访问的名称,因为它指向的元素不存在。如果它指向的元素是隐藏的(而不是不存在的),则可以计算可访问的名称,如Accessible Name and Description Computation的步骤2A中所述。
屏幕阅读器用户可以使用快捷键,使导航快速简便。如果我想导航到页面上的下一个按钮,我只需按“B”(屏幕阅读器正在运行),我的焦点将移动到下一个按钮。该按钮的名称将被公布,但如果它指向的元素不存在,则没有名称可以宣布。
我也可以通过按ctrl + ins + b打开一个对话框,其中包含页面上所有按钮的列表(如果我正在使用JAWS屏幕阅读器)。该列表将显示所有按钮的可访问名称。同样,如果您的按钮指向不存在的元素,则该对话框中将不会显示名称。
使用iOS上的VoiceOver,我可以设置我的转子按钮导航,这样当我向上或向下滑动时,焦点移动到下一个按钮(类似于用PC屏幕阅读器按'B')。当焦点移动到下一个按钮时,将计算并公布其名称。因此,如果它指向的元素不存在,则不会公布名称。
所以对你的问题的简单回答是使用隐藏元素而不是在DOM中创建/销毁的元素,但我想在这个答案背后给出一些背景。