はじめに
Webアプリケーションでユーザーに情報を伝える場面は多い。「保存しました」「エラーです」「このボタンは○○です」——これらは視覚的には実装できていても、スクリーンリーダー利用者に適切に伝わっているだろうか。
WAI-ARIA APG(Authoring Practices Guide)では、通知系のパターンとして status、alert、tooltip の3つを定義している。本記事ではそれぞれの違いと使い分けを整理する。
3パターンの比較表
| 項目 | status | alert | tooltip |
|---|---|---|---|
| 目的 | 控えめな通知 | 緊急の通知 | 補足説明 |
| role属性 | status | alert | tooltip |
| aria-live(暗黙値) | polite | assertive | なし |
| aria-atomic(暗黙値) | true | true | - |
| フォーカス移動 | しない | しない | しない |
| 表示トリガー | DOM変更 | DOM変更 | フォーカス/ホバー |
| 自動消去 | NG | NG | ホバー/フォーカス外れで消える |
最大の違いは aria-live の値 である。これがスクリーンリーダーの読み上げタイミングを決定する。
status(role="status")
ユーザーの作業を中断せずに、状態の変化を控えめに伝えるパターン。
暗黙のプロパティ
aria-live="polite"— スクリーンリーダーは現在の読み上げを終えてから通知するaria-atomic="true"— 変更部分だけでなくコンテナ全体を読み上げる
ユースケース
- 検索結果件数の更新
- フォームの保存完了メッセージ
- ショッピングカートの合計金額更新
- ファイルアップロード進捗
実装例
<div role="status">5件の結果が見つかりました</div>
HTML5の <output> 要素は暗黙的に role="status" を持つ。
<output>計算結果: 42</output>
注意点
- 自動的に消えるメッセージにしてはいけない(WCAG 2.2.3 違反)
- ページロード時に既に存在する status は読み上げられない。動的に変更されたもののみ対象
alert(role="alert")
緊急性の高い情報を即座にユーザーに伝えるパターン。
暗黙のプロパティ
aria-live="assertive"— 現在の読み上げを中断して即座に通知するaria-atomic="true"
ユースケース
- バリデーションエラー
- ネットワーク接続の切断
- セッションタイムアウト警告
- 重要なシステムメッセージ
実装例
<div role="alert">メールアドレスの形式が正しくありません</div>
注意点
- フォーカスは移動しない(フォーカスを移動させたい場合は
alertdialogを使う) - 頻繁に発火させるとユーザー体験を著しく損なう(WCAG 2.2.4)
- こちらも自動消去NG
alert と alertdialog の違い
| alert | alertdialog | |
|---|---|---|
| フォーカス移動 | なし | ダイアログに移動 |
| ユーザーの応答 | 不要 | 必要(確認ボタン等) |
| モーダル | No | Yes |
「エラーがあります」と伝えるだけなら alert。「本当に削除しますか?」のように応答が必要なら alertdialog を使う。
tooltip(role="tooltip")
要素に対する補足情報をポップアップで表示するパターン。
特徴
- ライブリージョンではない(
aria-liveなし) - スクリーンリーダーはトリガー要素にフォーカスした時点で
aria-describedby経由で読み上げる - フォーカスまたはホバーで表示、Escape で閉じる
実装例
<button aria-describedby="save-tip">💾</button>
<div role="tooltip" id="save-tip">ファイルを保存する</div>
キーボード操作
- Escape: ツールチップを閉じる
- フォーカスがトリガー上にある間は表示維持
- フォーカスが外れると非表示
注意点
- tooltip内にリンクやボタンなどフォーカス可能な要素を入れてはいけない
- フォーカス可能な内容が必要な場合は non-modal dialog を使う
- APG公式ではまだ「work in progress」(正式な実装例なし)
使い分けフローチャート
ユーザーに情報を伝えたい
│
├── ユーザーの応答が必要?
│ └── Yes → alertdialog(モーダル)
│
├── 緊急性が高い?(エラー、警告)
│ └── Yes → alert
│
├── 状態変化の通知?(保存完了、件数更新)
│ └── Yes → status
│
└── 要素の補足説明?(アイコンの意味、入力ヒント)
└── Yes → tooltip
よくある誤り
| 誤り | 問題 | 正しい実装 |
|---|---|---|
保存完了に role="alert" | 緊急ではないのに読み上げを中断する | role="status" を使う |
| エラーメッセージに role なし | スクリーンリーダーに通知されない | role="alert" を付ける |
| tooltip 内にリンクを配置 | フォーカス不可能で操作できない | non-modal dialog にする |
aria-live="polite" を明示的に書く | 冗長(status は暗黙で持つ) | role だけ指定すれば十分 |
| 通知を3秒後に自動消去 | WCAG 2.2.3 違反 | 消去しないか、ユーザー操作で消す |
aria-live の値と挙動まとめ
| 値 | 挙動 | 対応 role |
|---|---|---|
off | 通知しない(デフォルト) | - |
polite | アイドル時に読み上げ | status, log |
assertive | 即座に割り込み読み上げ | alert |
aria-live を直接指定するのではなく、適切な role を使うことで暗黙的に設定されるのがベストプラクティスである。
まとめ
- status: 控えめ。ユーザーの手が空いたら伝える。保存完了や件数更新に最適
- alert: 緊急。今すぐ伝える。エラーや警告に限定して使う
- tooltip: 通知ではない。要素の補足説明。
aria-describedbyで紐付ける
3つともフォーカスを移動しない点は共通している。フォーカス移動が必要なら alertdialog か dialog を検討する。
デモ(CodePenで試す)
以下の「Edit on CodePen」ボタンをクリックすると、CodePen上でコードを編集・実行できる。スクリーンリーダー(macOSならVoiceOver: Cmd+F5)を有効にして動作の違いを体感してほしい。