ARIA:button 角色
button
角色用于可单击的元素,在用户激活时触发响应。添加 role="button"
会告诉屏幕阅读器这个元素是个按钮,但是不提供按钮的功能。你应该使用的 <button>
或者 type="button"
的 <input>
。
描述
button 角色会向辅助技术(如屏幕阅读器)识别一个元素为按钮。按钮是用于执行操作的小部件,例如提交表单、打开对话框、退出活动或执行一个命令,例如插入新的记录或者显示信息。添加 role="button"
会告诉辅助技术,这是一个按钮,但是不提供按钮的功能。你应该使用 <button>
或者 <input>
以及 type="button"
。
button
角色可以和 aria-pressed
属性一起使用,以创建切换按钮。
<div id="saveChanges" tabindex="0" role="button" aria-pressed="false">保存</div>
上面这个例子创建了一个可聚焦的按钮,但是需要 JavaScript 和 CSS 来包含按钮的外观和行为。这些功能默认是由 <button>
或者 <input>
(带有 type="button"
)元素提供的。
<button type="button" id="saveChanges">保存</button>
备注:如果使用 role="button"
而不是语义化的 <button>
或 <input type="button">
你需要让这个元素可聚焦并定义 click
和 keydown
事件的事件处理器。这包括了对按下 Enter 和 Space 的事件的处理,以处理各种形式的用户输入。参见官方的 WAI-ARIA 示例代码。
除了常见的按钮部件之外,使用非按钮元素创建切换按钮和菜单按钮时,应该使用 role="button"
。
切换按钮是指有两个状态的按钮,可以是关(未按下)或者开(已按下)。aria-pressed
属性值 true
或 false
会将按钮识别为切换按钮。
菜单按钮是指控制一个菜单且 aria-haspopup
属性设置为 menu
或 true
的按钮。
所有子元素都是仅作展示的
有些类型的用户界面元件,呈现在平台无障碍 API 中时,仅可包含文本。无障碍 API 没有呈现 button
中包含的语义元素的方式。要处理这个限制,浏览器会自动为任何 button
的后代元素应用角色 presentation
,因为按钮这种角色不支持带有语义的子元素。
例如,考虑以下包含标题的 button
元素。
<div role="button"><h3>按钮的标题</h3></div>
由于 button
的子元素都是仅作展示的,因此相当于以下的代码:
<div role="button"><h3 role="presentation">按钮的标题</h3></div>
从辅助技术的视角来看,这个标题不存在,因为前面的代码片段在无障碍树中相当于以下内容:
<div role="button">按钮的标题</div>
关联的 ARIA 角色、状态和属性
aria-pressed
-
aria-pressed
属性将按钮定义为切换按钮。此值描述了按钮的状态。值包括aria-pressed="false"
(按钮还没有被按下)、aria-pressed="true"
(按钮当前已被按下)和aria-pressed="mixed"
(按钮被视为部分按下)。如果此属性被忽略,或者设置为默认值aria-pressed="undefined"
,那么元素不支持被按下。 aria-expanded
-
如果按钮控制了其他元素的分组,
aria-expanded
状态指示了被控制的分组当前是被展开还是折叠。如果按钮设置了aria-expanded="false"
,则分组当前未展开;如果按钮设置了aria-expanded="true"
,则分组当前已展开;如果按钮设置了aria-expanded="undefined"
,则其是不可展开的。
基本的按钮
按钮始终应该有无障碍的名称。对于大多数的按钮,名称通常是和按钮内的文本、开启和闭合标签之间的内容一致的。一些情况下,比如以图标形式呈现的按钮,其无障碍名称可能是由 aria-label
或者 aria-labelledby
属性提供的。
切换按钮
切换按钮通常有两种状态:按下、没有按下,第三种混合状态可用于控制了其他的元素的切换按钮,例如其他的不共享同一个值的切换按钮或者复选框。还可以使用 button
角色(如果元素不是原生的 button 元素)加 aria-pressed
属性来表示元素是否为切换按钮:
- 如果没有
aria-pressed
,说明这不是一个切换按钮。 - 如果
aria-pressed="false"
,说明这个按钮当前没有被按下。 - 如果
aria-pressed="true"
。说明这个按钮当前已被按下。 - 如果
aria-pressed="mixed"
,说明这个按钮被认为是部分按下的。
比如,音频播放器上有“静音”标签的静音按钮应该表示当 aria-pressed
状态为 true 时声音是静音的。切换按钮的标签不应该随状态改变而改变。在这个例子中,当屏幕阅读器说“静音切换按钮已按下”或者“静音切换按钮未按下”(取决于 aria-pressed
时),按钮的标签都始终为“静音”。如果设计时是要让按钮标签由“静音”更改为“取消静音”,那么这时候切换按钮并不合适,aria-pressed
属性应该省略。
键盘交互
按键 | 功能 |
---|---|
Enter | 激活按钮。 |
Space | 激活按钮。 |
按钮激活后,会根据按钮执行的操作的类型设置焦点。比如,如果点击打开对话框的按钮,那么焦点应该移动到对话框。如果按钮是关闭对话框的,那么焦点应该回到打开对话框的按钮,除非对话框上下文中执行的功能在逻辑上是导向到不同的元素的。如果按钮更改了当前的上下文,例如将音频文件静音或者取消静音,那么焦点通常应该留在按钮上。
必需的 JavaScript 特性
必需的事件处理器
按钮可能是由鼠标、触屏或者键盘用户操作的。对于原生的 <button>
元素,按钮的 onclick
事件会在用户点击时,以及在按钮被聚焦且用户按下 Space 或 Enter 时触发。但如果使用其他标签创建按钮,那么 onclick
事件只会在用户使用鼠标指针点击时才会触发,即使使用了 role="button"
。因此,需要给元素添加单独的事件处理器,以在按下 Space 或 Enter 键时触发按钮。
onclick
-
使用鼠标点击或者触摸事件激活按钮时产生的事件。
onKeyDown
-
使用键盘上的 Enter 或 Space 键激活按钮时触发的事件。(注意不是已弃用的 onKeyPress。)
示例
基本按钮示例
在这个例子中,span 元素有个 button
角色。由于使用了 <span>
元素,需要使用 tabindex
属性以使得按钮可聚焦,并成为页面的 tab 顺序的一部分。还有包含 CSS 样式,以使得这个 <span>
元素看上去像是个按钮,并在按钮被聚焦时,提供了视觉呈现。
handleBtnClick
和 handleBtnKeyDown
事件处理器执行了按钮在鼠标单击或者按下 Space 或 Enter 键的操作。在这个例子中,操作是给名字列表添加一个新的名字。
在文本框中添加名称以尝试这个例子。按钮会给列表添加一个新的名字。
HTML
<h1>ARIA 按钮示例</h1>
<ul id="nameList"></ul>
<label for="newName">输入你的名字:</label>
<input type="text" id="newName" />
<span
role="button"
tabindex="0"
onclick="handleCommand(event)"
onKeyDown="handleCommand(event)"
>添加名字</span
>
CSS
[role="button"] {
padding: 2px;
background-color: navy;
color: white;
cursor: default;
}
[role="button"]:hover,
[role="button"]:focus,
[role="button"]:active {
background-color: white;
color: navy;
}
ul {
list-style: none;
}
JavaScript
function handleCommand(event) {
// 处理鼠标单击以及 Enter 或 Space 的按键激活
// 除 Enter 或 Space 之外的按键不应该触发命令
if (
event instanceof KeyboardEvent &&
event.key !== "Enter" &&
event.key !== " "
) {
return;
}
// 从输入框中获取新的名字
const newNameInput = document.getElementById("newName");
const name = newNameInput.value;
newNameInput.value = ""; // 清除文本框
newNameInput.focus(); // 给予文本框焦点,以允许添加额外的名称。
// 不要在列表中添加空白项。
if (name.length > 0) {
const listItem = document.createElement("li");
listItem.appendChild(document.createTextNode(name));
// 在列表中添加新的名字。
const list = document.getElementById("nameList");
list.appendChild(listItem);
}
}
切换按钮示例
在这个片段中,使用 button
角色和 aria-pressed
属性,以将 <span>
元素转换为切换按钮,按钮被激活时,aria-pressed
的值在 true
和 false
之间切换。
HTML
<button
type="button"
onclick="handleBtnClick(event)"
onKeyDown="handleBtnKeyDown(event)">
静音音频
</button>
<span
role="button"
tabindex="0"
aria-pressed="false"
onclick="handleBtnClick(event)"
onKeyDown="handleBtnKeyDown(event)">
静音音频
</span>
<audio
id="audio"
src="https://soundbible.com/mp3/Tyrannosaurus%20Rex%20Roar-SoundBible.com-807702404.mp3">
你的浏览器不支持 `audio` 元素。
</audio>
CSS
button,
[role="button"] {
padding: 3px;
border: 2px solid transparent;
}
button:active,
button:focus,
[role="button"][aria-pressed="true"] {
border: 2px solid #000;
}
JavaScript
function handleBtnClick(event) {
toggleButton(event.target);
}
function handleBtnKeyDown(event) {
// 检查 space 或 enter 是否已按下
// "Spacebar" 是为 IE11 支持
if (event.key === " " || event.key === "Enter" || event.key === "Spacebar") {
// 避免按下空格键时滚动屏幕的默认操作
event.preventDefault();
toggleButton(event.target);
}
}
function toggleButton(element) {
const audio = document.getElementById("audio");
// 检查按钮是否已按下
const pressed = element.getAttribute("aria-pressed") === "true";
// 将 aria-pressed 设为相反的状态
element.setAttribute("aria-pressed", !pressed);
// 切换音频文件的播放状态
if (pressed) {
audio.pause();
} else {
audio.play();
}
}
结果
无障碍考虑
按钮本身是可交互的,因此可聚焦。如果给自身不可聚焦的元素(如 <span>
、<div>
或 <p>
)添加了 button
角色,那么就应该使用 tabindex
属性以使得按钮可聚焦。
警告:谨慎将链接标记为按钮。按钮是预期使用 Space 或 Enter 键触发的,而链接是预期使用 Enter 触发的。也就是说,如果将链接用作按钮,仅添加 role="button"
是不够的。还有必要为 Space 键添加一个按键事件处理器,以与原生按钮的行为保持一致。
使用了 button
角色时,屏幕阅读器会声明其说成是一个按钮,通常是说“单击(click)”然后是其无障碍名称。无障碍名称是元素的内容,或是 aria-label
的值,或是由 aria-labelledby
属性引用的元素的值,或是描述(如果已包括)。
最佳实践
如果链接执行的是按钮的操作,那么为元素设置 role="button"
可以帮助辅助技术用户理解这个元素的功能。然而,更好的设计是调整视觉设计从而匹配其功能和 ARIA 角色。如果可能,建议使用原生的 HTML 按钮(<button>
、<input type="button">
、<input type="submit">
、<input type="reset">
和 <input type="image">
)而不是 button
角色,因为原生 HTML 按钮能够被所有的用户代理和辅助技术所支持,且默认会提供键盘和聚焦需求而不需要额外的自定义。
规范
Specification |
---|
Accessible Rich Internet Applications (WAI-ARIA) # button |
Unknown specification |