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 的功能。