ARIA
ARIA の第一の規則は、ARIA を使わないことです。ふさわしい HTML の要素があるなら、それが答えです。
図の中身を文字で読む
- ARIA を使う前に アクセシブルネームの優先順位
- ある
- 適切な HTML 要素があるか?
- ない
- タブ・ツリーなど
- 標準にない部品
- それを使う。ARIA は書かない
- button・a href・nav・main・h1〜h6
- ARIA で役割・状態・関係を伝える
- キーボード操作は自前で実装することになる
- 上が存在すると、下は無視される
- 1 aria-labelledby
- 2 aria-label
- 3 label for / alt / caption
- 4 要素の中身のテキスト
- 5 title 属性
- 不正確な ARIA は、何も付けないより有害。誤った操作方法を試させることになる。
- ✕ 見えているテキストと違う名前
- 動的な変化を読み上げに伝えるには、空のライブリージョンを先に置き、中身だけを差し替える。
- 要素ごと後から追加すると、多くの環境で検出されない。
- assertive は読み上げに割り込むので、エラーなど緊急のものに限る。
- 「お問い合わせを送信する」と書いてあるのにaria-label="送信" にすると、音声入力で見えている語で指示できなくなる。
ひと目で#
第一の規則は「ARIA を使わないこと」。 ふさわしい HTML の要素があるなら、それを使います。
- ARIA
- HTML だけでは表せない役割、状態、関係を伝える属性の集まり
- ロール
- その要素が何であるか(
role="tab") - アクセシブルネーム
- 読み上げられる名前。どこから取るかに優先順位がある
- ライブリージョン
- 動的な変化を自動で読み上げさせる領域
アクセシブルネームの優先順位#
上のものがあれば、下は無視されます。
| 順位 | 取る元 |
|---|---|
| 1 | aria-labelledby |
| 2 | aria-label |
| 3 | <label for> / alt / <caption> |
| 4 | 要素の中身のテキスト |
| 5 | title 属性 |
4つ書いても、読まれるのは1つだけです。念のために足した title は、上に何かある限り一度も届きません。
図の中身を文字で読む
- 4つ書いても、読み上げられるのは1つだけ
- 上にあるものが勝ち、下は無視される。全部足しても足し算にはならない
- 保存 aria-labelledby="h1" これが読まれる
- aria-label="下書きを保存" 無視
- 1つのボタンに、4つの元
- 要素の中身「保存」 無視
- title="保存ボタン" 無視
- ✕ 見えている文字と違う名前を与える ○ 見えている文字を、そのまま名前にする
- 送信 申込を確定する
- aria-label="申込を確定" ボタンの文言のほうを、結果が分かる語に直す
- 音声入力で「送信」と言っても、この操作は動かない 見えている語と読み上げが一致し、声でも指せる
使い分け#
| こういうとき | やること |
|---|---|
| ボタン、リンク、見出し、一覧 | 標準の要素を使う。ARIA は書かない |
| タブやツリーなど、標準にない部品 | ARIA で役割と状態を伝える。キー操作は自前で作る |
| アイコンだけのボタン | aria-label で名前を与える |
| 開閉する要素 | aria-expanded |
| 件数の更新、保存の完了 | role="status"(polite) |
| エラーの発生 | role="alert"(assertive) |
間違えやすいところ#
- 標準の要素があるのに ARIA で代用する
tabindexと Enter / Space の処理を自前で書くことになる - 正しくない役割を付ける何も付けないより害がある。誤った操作を試させる
- 見えている文字と違う名前を与える音声入力で、見えている語では指示できなくなる
aria-labelを多用する翻訳ツールで訳されないことがあり、保守もしにくい- ライブリージョンをあとから要素ごと足す多くの環境で検出されない。空の領域を先に置く
assertiveを多用する読み上げがたびたび途切れ、操作の邪魔になるrole="presentation"を安易に使う意味のある要素から意味を奪う
もっと小さい部品のレシピ#
検索フォーム、通知の領域、展開するボタン、現在地のナビ。印を1つ2つ足すだけで済む4件は、よく使うARIAのレシピにまとめてあります。
直す例#
架空の案件を1つ例にとります。どこを見て、何をどう直すかを書きます。
例として、前任者が「アクセシビリティ対応」として、<div> に role="button" を足して回っていました。読み上げは「ボタン」と言うのに、Tab では止まらず、Enter も Space も効きません。役割の名乗りだけがあって、中身がない状態です。
やることは足すのではなく、戻すことです。<button> に替えると、フォーカス、Enter と Space の実行、無効状態の伝達が、まとめて付いてきます。ARIA は HTML を補うもので、置き換えるものではありません。
戻しきったあとに残ったのは、標準の要素に無い部品が3つです。お知らせのタブ切替、カートの件数表示、アイコンだけの削除ボタン。タブは role="tab" と aria-selected に加えて、左右キーの処理を自分で書きます。件数は空の role="status" を先に置き、中身のテキストだけを差し替えます。要素ごとあとから足すと、多くの環境で検出されません。削除ボタンには aria-label="この商品を削除" を与えます。
このとき、見えている文字と違う名前を付けないことに気をつけます。ボタンに「送信」と書いて aria-label="申込を確定" にすると、音声入力で「送信」と言っても動きません。名前を変えたいなら、ボタンの文言のほうを書き直します。
確認する#
<button>や<a>で足りるところにroleが付いていない- 見えている文字と、読み上げられる名前が同じ語になっている
- ライブリージョンが空のまま先に置かれ、中身だけ差し替わっている
使えるパターン#
この話が要る場面#
このページが答えになる、現場の困り事です。困り事の側から探すと、同じ場所に着きます。
aria-label で機能名を与える。見えているテキストがあるなら、それと違う名前にしない。
このコードで動いている見本です
役割が要素と食い違っている。まず適切なHTML要素に替える。ARIAは足りないときだけ。
このコードで動いている見本です
空のライブリージョンを先に置き、中身だけ差し替える。要素ごと後から足すと検出されない。
このコードで動いている見本です
この場面のほかの困り事と、そのまま貼れる部品は誰でも使えるようにするにまとめてある。逆引きには全188件。
部品から作る#
部品を選ぶと、動く見本とキー操作の注釈つきの完成HTMLが出ます。見本は実物なので、Tab や矢印キーでそのまま操作できます。役割やキー操作を省いた部品は、何も付けないより害になります。形を変えずに使ってください。
重要なお知らせが3件あります。
更新情報が5件あります。
採用情報が1件あります。
- aria-selected の切替、tabindex の付け替え、パネルの hidden は、すべて JS で更新する
- パネルの tabindex="0" は、中に操作要素がなくてもキーボードで読みに入るための指定
- 出典: WAI-ARIA APG「Tabs Pattern」。移動と同時に切り替える自動方式
<div role="tablist" aria-label="お知らせの種類">
<!-- 選択中のタブだけが Tab で止まる(ロービングタブインデックス) -->
<button type="button" role="tab" id="tab-1" aria-controls="panel-1" aria-selected="true">重要</button>
<button type="button" role="tab" id="tab-2" aria-controls="panel-2" aria-selected="false" tabindex="-1">更新</button>
<button type="button" role="tab" id="tab-3" aria-controls="panel-3" aria-selected="false" tabindex="-1">採用</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1" tabindex="0">…</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" tabindex="0" hidden>…</div>
<div role="tabpanel" id="panel-3" aria-labelledby="tab-3" tabindex="0" hidden>…</div>
<!-- JS で作るキー操作(click と keydown の両方を書く)
← → タブを移動して、その場で切り替える(端で折り返す)
Home End 最初 / 最後のタブへ
Tab タブ列から抜けて、表示中のパネルへ -->
/* 添えるCSS */
[role="tablist"] { display: flex; gap: var(--space-1); border-block-end: 1px solid var(--color-border); }
[role="tab"] { font: inherit; padding: var(--space-2) var(--space-4); background: none; border: 0; cursor: pointer; }
[role="tab"][aria-selected="true"] { font-weight: 700; box-shadow: inset 0 -2px 0 var(--color-accent-text); }
[role="tabpanel"] { padding-block: var(--space-4); }
この道具は JavaScript で動きます。無効の場合は、出典の WAI-ARIA Authoring Practices Guide から該当パターンを写してください。