ARIA:radio 角色

radio 角色是一組可選單選按鈕中的一部分,位於 radiogroup 中,一次只能選中一個單選按鈕。

描述

單選按鈕是一個可選輸入,當與其他單選按鈕關聯時,一次只能選中其中一個。單選按鈕必須在 radiogroup 中組合在一起,以指示哪些按鈕影響相同的值。

html
<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>),它本身提供了所有必需的功能

html
<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-checkedmixed 無效。

如果選中了單選按鈕,則單選按鈕元素的 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 元素,其中包含一個標題。

html
<div role="radio"><h6>name of my radio</h6></div>

由於 radio 的後代是表示性的,因此以下程式碼等效

html
<div role="radio"><h6 role="presentation">name of my radio</h6></div>

從輔助技術使用者的角度來看,標題不存在,因為前面的程式碼片段在 輔助功能樹 中等效於以下內容

html
<div role="radio">name of my radio</div>

關聯的 WAI-ARIA 角色、狀態和屬性

radiogroup 角色

單選按鈕包含在或屬於具有 radiogroup 角色的元素中。如果無法在標記中巢狀在 radiogroup 內,則 radiogrouparia-owns 屬性包含組中未巢狀的單選按鈕的 id 值。

aria-checked

aria-checked 的值定義了單選按鈕的狀態。當與單選按鈕元素一起使用時,該屬性具有兩個可能的值之一

true

單選按鈕被選中。

false

單選按鈕未被選中。

注意:如果在預設情況下不接受鍵盤焦點的元素(例如,<div><span>)上使用 role="radio",請使用 tabindex 屬性

鍵盤互動

Tab + Shift

將焦點移入和移出單選按鈕組。當焦點移入單選按鈕組時,如果某個單選按鈕已被選中,則焦點將設定在選中的按鈕上。如果沒有任何單選按鈕被選中,則焦點將設定在組中的第一個單選按鈕上。

空格鍵

如果單選按鈕未被選中,則選中它。取消選中單選按鈕組中先前選中的單選按鈕。

右箭頭下箭頭

將焦點移動到組中的下一個單選按鈕並選中它,同時取消選中先前獲得焦點的單選按鈕。如果焦點位於最後一個單選按鈕上,則焦點將移動到第一個單選按鈕。

左箭頭上箭頭

將焦點移動到組中的上一個單選按鈕並選中它,同時取消選中先前獲得焦點的單選按鈕。如果焦點位於第一個單選按鈕上,則焦點將移動到最後一個單選按鈕。

工具欄中的單選按鈕

由於箭頭鍵用於在工具欄元素之間導航,並且 Tab 鍵用於將焦點移入和移出工具欄,因此當單選按鈕組巢狀在工具欄中時,單選按鈕組的鍵盤互動方式略有不同於不在工具欄內的單選按鈕組。有關更多資訊,請參閱 radiogroup 鍵盤互動

必需的 JavaScript

onClick

處理單選按鈕和關聯標籤上的滑鼠點選,這將透過更改 aria-checked 屬性的值以及單選按鈕的外觀(使其對視力正常的使用者顯示為選中或未選中)來更改單選按鈕的狀態。

onKeyPress

處理使用者按下 空格鍵 以更改單選按鈕狀態的情況,這將透過更改 aria-checked 屬性的值以及單選按鈕的外觀(使其對視力正常的使用者顯示為選中或未選中)來更改單選按鈕的狀態。

示例

以下示例使用 ARIA 將其他通用元素修改為單選按鈕。CSS 和 JavaScript 用於視覺上和程式設計方式地修改元素的選中或未選中狀態。

HTML

html
<div role="radiogroup" aria-labelledby="legend" id="radiogroup">
  <p id="legend">
    Should you be using the <code>radio</code> role or
    <code>&lt;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>&lt;input type="radio"></code></label>
  </div>
</div>

CSS

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 元素轉換為單選按鈕。

js
// 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)。

html
<fieldset>
  <legend>
    Should you be using the <code>radio</code> role or
    <code>&lt;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>&lt;input type="radio"></code></label>
  </div>
</fieldset>

最佳實踐

ARIA 的第一條規則是:如果本機 HTML 元素或屬性具有您所需的語義和行為,請使用它,而不是重新利用元素並新增 ARIA 角色、狀態或屬性使其可訪問。因此,建議使用本機 HTML 單選按鈕 表單控制元件,而不是使用 JavaScript 和 ARIA 重新建立單選按鈕的功能。

另請參閱