ARIA: radio role
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 radio
原生提供的所有功能都需要通过 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">
)有两种状态(“checked” 或 “not checked”)。同样,具有 role="radio"
的元素可以通过 aria-checked
属性暴露两种状态:true
表示选中状态,false
表示未选中状态。aria-checked
的 mixed
值不能用于单选按钮。
如果单选按钮被选中,则 radio 元素将 aria-checked
设置为 true
。如果未选中,则将其设置为 false
。
每个单选按钮元素都具有 radio
角色。radio 角色应始终与其他关联的 radio 一起嵌套在 radiogroup
中。如果无法在标记中将单选按钮嵌套在 radio 组中,请使用非分组 radio 的 id
作为 radiogroup
元素上 aria-owns
属性的值,该值以空格分隔,以指示 radiogroup
与其 radio 成员的关系。
每个 radio 元素都可以通过其内容进行标记,或者由 aria-labelledby
引用的可见标签进行标记,或者通过 aria-label
指定标签。包含的 radiogroup
元素应通过 aria-labelledby
引用的可见标签进行标记,或通过 aria-label
指定标签。如果存在提供关于 radio 组或每个 radio 按钮的附加信息的元素,则这些元素应由 radiogroup
元素或 radio 元素使用 aria-describedby
属性进行引用。
由于 radio
是一个交互式控件;它必须是可聚焦的并且可以通过键盘访问。如果将角色应用于非聚焦元素,请使用 tabindex
属性进行更改。激活 radio 的预期键盘快捷键是 Space 键。当 radio 被选中时,使用 JavaScript 将 aria-checked
属性切换为 true
,并确保组中的所有其他 radio 角色都设置为 aria-checked="false"
。
为了以编程方式指示必须从 radio 组中选择一个单选按钮,必须在 radiogroup
元素上指定值为 true
的 aria-required
属性。不建议在单独的 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
的值定义了 radio 的状态。与 radio 元素一起使用时,该属性具有以下两种可能的值之一:
注意: 如果 role="radio"
用于一个不原生接受键盘焦点的元素,请使用 tabindex
属性。例如,<div>
或 <span>
。
键盘交互
- Tab + Shift
-
将焦点移入和移出 radio 组。当焦点移入 radio 组,并且已选中某个 radio 按钮时,焦点将设置在已选中的按钮上。如果所有 radio 按钮都未选中,焦点将设置在组中的第一个 radio 按钮上。
- 空格
-
如果 radio 未被选中,则选中它。取消选中 radio 组中之前已选中的 radio 按钮。
- 右箭头键 和 下箭头键
-
将焦点移至组中的下一个 radio 按钮并选中它,同时取消选中之前具有焦点的 radio 按钮。如果焦点在最后一个 radio 按钮上,焦点将移至第一个 radio 按钮。
- 左箭头键 和 上箭头键
-
将焦点移至组中的上一个 radio 按钮并选中它,同时取消选中之前具有焦点的 radio 按钮。如果焦点在第一个 radio 按钮上,焦点将移至最后一个 radio 按钮。
工具栏中的 radios
由于箭头键用于在工具栏元素之间导航,而 Tab 键用于将焦点移入和移出工具栏,因此当 radio 组嵌套在工具栏中时,radio 组的键盘交互与非嵌套在工具栏中的 radio 组略有不同。有关更多信息,请参阅 radiogroup
键盘交互。
必需的 JavaScript
onClick
-
处理对 radio 及其关联标签的鼠标点击,通过更改
aria-checked
属性的值来更改 radio 的状态,并改变 radio 的外观,使其对可见用户显示为已选中或未选中。 onKeyPress
-
处理用户按下 Space 键以更改 radio 的状态的情况,通过更改
aria-checked
属性的值来更改 radio 的状态,并改变 radio 的外观,使其对可见用户显示为已选中或未选中。
示例
以下示例使用 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
要将非语义 HTML 制作成单选按钮,需要大量的 JavaScript。
// initialize all the radio role elements
const radioGroups = document.querySelectorAll('[role="radiogroup"]');
for (const radioGroup of radioGroups) {
const radios = radioGroup.querySelectorAll("[role=radio]");
for (const radio of radios) {
radio.addEventListener("keydown", handleKeydown);
radio.addEventListener("click", handleClick);
}
}
// handle mouse and touch events
function handleClick(event) {
setChecked(this);
event.stopPropagation();
event.preventDefault();
}
// handle key presses
function handleKeydown(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
function setChecked() {
// 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 来重新创建 radio 的功能。