ARIA:radio 角色
radio
角色是一组可选单选按钮中的一部分,位于 radiogroup
中,一次只能选中一个单选按钮。
描述
单选按钮是一个可选输入,当与其他单选按钮关联时,一次只能选中其中一个。单选按钮必须在 radiogroup
中组合在一起,以指示哪些按钮影响相同的值。
<div role="radiogroup" aria-labelledby="legend25" id="radiogroup25">
<p id="legend25">Ipsum and lorem?</p>
<div>
<span
role="radio"
aria-checked="false"
tabindex="0"
aria-labelledby="q25_radio1-label"
data-value="True"></span>
<label id="q25_radio1-label">True</label>
</div>
<div>
<span
role="radio"
aria-checked="false"
tabindex="0"
aria-labelledby="q25_radio2-label"
data-value="False"></span>
<label id="q25_radio2-label">False</label>
</div>
<div>
<span
role="radio"
aria-checked="true"
tabindex="0"
aria-labelledby="q25_radio3-label"
data-value="huh?"></span>
<label id="q25_radio3-label">What is the question?</label>
</div>
</div>
role
属性仅添加语义;HTML 单选按钮 本身附带的所有功能都需要使用 JavaScript 和 HTML tabindex
属性添加。
注意:ARIA 的第一条规则是,如果本机 HTML 元素或属性具有您所需的功能和行为,请使用它,而不是重新利用元素并添加 ARIA。而是使用本机 HTML <input type="radio">
(以及关联的 <label>
),它本身提供了所有必需的功能
<fieldset>
<legend>Ipsum and lorem?</legend>
<div>
<input type="radio" value="True" id="q25_radio1" name="q25" />
<label for="q25_radio1">True</label>
</div>
<div>
<input type="radio" value="False" id="q25_radio2" name="q25" />
<label for="q25_radio2">False</label>
</div>
<div>
<input type="radio" value="huh?" id="q25_radio3" name="q25" checked />
<label for="q25_radio3">What is the question?</label>
</div>
</fieldset>
本机 HTML 单选表单控件 (<input type="radio">
) 有两种状态(“选中”或“未选中”)。类似地,具有 role="radio"
的元素可以通过 aria-checked
属性公开两种状态:true
表示选中状态,false
表示未选中状态。对于单选按钮,aria-checked
值 mixed
无效。
如果选中了单选按钮,则单选按钮元素的 aria-checked
设置为 true
。如果未选中,则其 aria-checked
设置为 false
。
每个单选按钮元素都具有角色 radio
。radio 角色应始终嵌套在 radiogroup
中的其他关联 radio 中。如果无法将单选按钮嵌套在 radio 组中,请在 radiogroup
元素的 aria-owns
属性的值中使用非分组 radio 的 id
作为以空格分隔的值列表,以指示 radiogroup
与其 radio 成员的关系。
每个 radio 元素都由其内容标记,具有 aria-labelledby
引用的可见标签,或使用 aria-label
指定的标签。包含的 radiogroup
元素应具有 aria-labelledby
引用的可见标签或使用 aria-label
指定的标签。如果存在提供有关 radio 组或每个 radio 按钮的其他信息的元素,则这些元素应由 radiogroup
元素或使用 aria-describedby
属性的 radio 元素引用。
由于 radio
是一个交互式控件;它必须可聚焦且可通过键盘访问。如果角色应用于不可聚焦的元素,请使用 tabindex
属性更改此设置。激活 radio 的预期键盘快捷键是 空格键。使用 JavaScript 将 aria-checked
属性切换到 true
,当 radio 被选中时,同时确保该组中的所有其他 radio 角色都设置为 aria-checked="false"
。
要以编程方式指示必须从 radio 组中选择单选按钮,必须在 radiogroup
元素上指定 aria-required
属性(值为 true
)。不建议在单个 ARIA 单选按钮上使用 aria-required
属性。
所有后代都是表示性的
某些类型的用户界面组件在平台辅助功能 API 中表示时,只能包含文本。辅助功能 API 没有方法表示包含在 radio
中的语义元素。为了解决此限制,浏览器会自动将角色 presentation
应用于任何 radio
元素的所有后代元素,因为它是一个不支持语义子元素的角色。
例如,考虑以下 radio
元素,其中包含一个标题。
<div role="radio"><h6>name of my radio</h6></div>
由于 radio
的后代是表示性的,因此以下代码等效
<div role="radio"><h6 role="presentation">name of my radio</h6></div>
从辅助技术用户的角度来看,标题不存在,因为前面的代码片段在 辅助功能树 中等效于以下内容
<div role="radio">name of my radio</div>
关联的 WAI-ARIA 角色、状态和属性
radiogroup
角色-
单选按钮包含在或属于具有
radiogroup
角色的元素中。如果无法在标记中嵌套在radiogroup
内,则radiogroup
的aria-owns
属性包含组中未嵌套的单选按钮的id
值。 aria-checked
-
aria-checked
的值定义了单选按钮的状态。当与单选按钮元素一起使用时,该属性具有两个可能的值之一
注意:如果在默认情况下不接受键盘焦点的元素(例如,<div>
或 <span>
)上使用 role="radio"
,请使用 tabindex
属性。
键盘交互
- Tab + Shift
-
将焦点移入和移出单选按钮组。当焦点移入单选按钮组时,如果某个单选按钮已被选中,则焦点将设置在选中的按钮上。如果没有任何单选按钮被选中,则焦点将设置在组中的第一个单选按钮上。
- 空格键
-
如果单选按钮未被选中,则选中它。取消选中单选按钮组中先前选中的单选按钮。
- 右箭头 和 下箭头
-
将焦点移动到组中的下一个单选按钮并选中它,同时取消选中先前获得焦点的单选按钮。如果焦点位于最后一个单选按钮上,则焦点将移动到第一个单选按钮。
- 左箭头 和 上箭头
-
将焦点移动到组中的上一个单选按钮并选中它,同时取消选中先前获得焦点的单选按钮。如果焦点位于第一个单选按钮上,则焦点将移动到最后一个单选按钮。
工具栏中的单选按钮
由于箭头键用于在工具栏元素之间导航,并且 Tab 键用于将焦点移入和移出工具栏,因此当单选按钮组嵌套在工具栏中时,单选按钮组的键盘交互方式略有不同于不在工具栏内的单选按钮组。有关更多信息,请参阅 radiogroup
键盘交互。
必需的 JavaScript
onClick
-
处理单选按钮和关联标签上的鼠标点击,这将通过更改
aria-checked
属性的值以及单选按钮的外观(使其对视力正常的用户显示为选中或未选中)来更改单选按钮的状态。 onKeyPress
-
处理用户按下 空格键 以更改单选按钮状态的情况,这将通过更改
aria-checked
属性的值以及单选按钮的外观(使其对视力正常的用户显示为选中或未选中)来更改单选按钮的状态。
示例
以下示例使用 ARIA 将其他通用元素修改为单选按钮。CSS 和 JavaScript 用于视觉上和编程方式地修改元素的选中或未选中状态。
HTML
<div role="radiogroup" aria-labelledby="legend" id="radiogroup">
<p id="legend">
Should you be using the <code>radio</code> role or
<code><input type="radio"></code>?
</p>
<div>
<span
role="radio"
aria-checked="true"
tabindex="0"
aria-labelledby="ariaLabel"
data-value="True"></span>
<label id="ariaLabel">ARIA role</label>
</div>
<div>
<span
role="radio"
aria-checked="false"
tabindex="0"
aria-labelledby="htmllabel"
data-value="False"></span>
<label id="htmllabel">HTML <code><input type="radio"></code></label>
</div>
</div>
CSS
[role="radio"] {
padding: 5px;
}
[role="radio"][aria-checked="true"]::before {
content: "(x)";
font-family: monospace;
}
[role="radio"][aria-checked="false"]::before {
content: "( )";
font-family: monospace;
}
JavaScript
需要大量的 JavaScript 代码才能将非语义 HTML 元素转换为单选按钮。
// initialize all the radio role elements
const radioGroups = document.querySelectorAll('[role="radiogroup"]');
for (let i = 0, groups = radioGroups.length; i < groups; i++) {
const radios = radioGroups[i].querySelectorAll("[role=radio]");
for (let j = 0, radiobuttons = radios.length; j < radios; j++) {
radios[j].addEventListener("keydown", function () {
handleKeydown();
});
radios[j].addEventListener("click", function () {
handleClick();
});
}
}
// handle mouse and touch events
let handleClick = function (event) {
setChecked(this);
event.stopPropagation();
event.preventDefault();
};
// handle key presses
let handleKeydown = function (event) {
switch (event.code) {
case "Space":
case "Enter":
currentChecked();
break;
case "ArrowUp":
case "ArrowLeft":
previousRadioChecked();
break;
case "ArrowDown":
case "ArrowRight":
nextItemChecked();
break;
default:
break;
}
event.stopPropagation();
event.preventDefault();
};
// when a radio is selected, give it focus, set checked to true;
// ensure all other radios in radio group are not checked
setChecked = function () {
// uncheck all the radios in group
// iterated through all the radios in radio group
// eachRadio.tabIndex = -1;
// eachRadio.setAttribute('aria-checked', 'false');
// set the selected radio to checked
// thisRadio.setAttribute('aria-checked', 'true');
// thisRadio.tabIndex = 0;
// thisRadio.focus();
// set the value of the radioGroup to the value of the currently selected radio
};
如果我们使用语义 HTML 元素,并且一组单选按钮中每个单选按钮的名称都相同,则不需要 JavaScript(甚至 CSS)。
<fieldset>
<legend>
Should you be using the <code>radio</code> role or
<code><input type="radio"></code>?
</legend>
<div>
<input type="radio" name="bestPractices" id="ariaLabel" value="True" />
<label for="ariaLabel">ARIA role</label>
</div>
<div>
<input type="radio" name="bestPractices" id="htmllabel" value="False" />
<label for="htmllabel">HTML <code><input type="radio"></code></label>
</div>
</fieldset>
最佳实践
ARIA 的第一条规则是:如果本机 HTML 元素或属性具有您所需的语义和行为,请使用它,而不是重新利用元素并添加 ARIA 角色、状态或属性使其可访问。因此,建议使用本机 HTML 单选按钮 表单控件,而不是使用 JavaScript 和 ARIA 重新创建单选按钮的功能。