基本的なアクセシビリティ対応に慣れてきたら、次のステップは「実際のユーザー体験をより向上する工夫」です。
DOMの構造やARIA属性、キーボード操作への対応などを取り入れることでより多くのユーザーが安心して利用できるサイトになります。
本記事では、より応用的なアクセシビリティ対応を紹介します。

読み上げ順を考慮する

スクリーンリーダーはDOMに従ってコンテンツを読み上げます。見た目の並びと読み上げ順が異なると、利用者は文脈を正しく理解できなくなる可能性があります。レイアウト調整のためにCSSで要素の表示順を入れ替える場合は、見た目と論理的な順序が一致するように設計しましょう。

関連するWCAG達成基準

WCAG 2.1 – 1.3.2 意味のあるシーケンスを理解する

未対応時のユーザーへの影響

内容が理解しにくくなる

見た目と違う順番で情報が伝わると文章や操作の意図を正しく理解できなくなります。
例:「本文」より先に「補足」が読み上げられて、何の説明か分からない。

実装方法

DOMの順序を論理的に保つ

情報の流れに沿ってHTML を記述します。
見た目はCSSで調整し、HTMLの順序を入れ替えないようにします。
CSSのorderrow-reverseなどの並び替えプロパティは見た目だけを変更するので、使用する際はDOMの順番に注意しましょう。

対応するブラウザは限られますが、reading-flowreading-orderというCSSプロパティが登場し、DOMの読み上げ順を制御できるようになりました。
今後広く実装されると、新たなアクセシビリティ対応の手段として活用されることが期待されます。
reading-flow
reading-order

モーダルやダイアログはトリガー直後に置く

モーダルをHTMLの最後に置くと読み上げ順が不自然になります。
出来るだけ表示トリガーの直後にモーダルを配置しましょう。そうすることによりスクリーンリーダー利用者が、モーダルを表示した直後に自然に内容にアクセスできます。
さらに、フォーカスをモーダル内に移動させ、閉じる際には元のトリガーボタンに戻す実装も行うとより確実です。

ARIA属性で状態や役割を伝える

見た目だけでは伝わらないUIコンポーネントの状態や役割を、スクリーンリーダーなどの支援技術に伝えるためにARIA属性を活用しましょう。
メニューの「開閉状態」、フォームの「エラー通知」など、適切なARIA 属性を付与することで利用者に正しく伝わります。

関連するWCAG達成基準

WCAG 2.1 – 4.1.2 名前・役割及び値
WCAG 2.1 – 4.1.3 ステータスメッセージ

未対応時のユーザーへの影響

状態が伝わらない

例えばメニューが開いているか閉じているかがスクリーンリーダーに伝わらないと、利用者は操作の結果を把握できず混乱します。

重要な通知を見逃す

入力エラーや処理完了メッセージがスクリーンリーダーに伝わらなければ、ユーザーは次にどう進めばよいか分からなくなります。

実装方法

コンポーネントごとに具体的な使用例の一部をまとめました

メニュー(開閉状態を伝える)

aria-expanded: 開閉状態を伝える
aria-controls: id属性で指定したメニューと紐付ける

<button aria-expanded="false" aria-controls="menu1">
  メニューを開く
</button>
<ul id="menu1" hidden>
  <li><a href="/profile">プロフィール</a></li>
  <li><a href="/settings">設定</a></li>
</ul>

タブ(開閉状態を伝える)

role=”tablist”: タブの集合であることを伝える
role=”tab” + aria-selected: 現在の選択状態を伝える
aria-controls”: id属性で指定した内容を紐付ける

<div role="tablist" aria-label="商品情報タブ">
  <button role="tab" aria-selected="true" aria-controls="tab1">概要</button>
  <button role="tab" aria-selected="false" aria-controls="tab2">レビュー</button>
</div>
<div id="tab1" role="tabpanel">商品の概要テキスト…</div>
<div id="tab2" role="tabpanel" hidden>レビューの内容…</div>

モーダル

role=”dialog”: ダイアログであることを伝える
aria-modal=”true”: ダイアログが開いている間、背後のコンテンツが操作できないことを伝える
aria-labelledby: id属性で指定したタイトルと紐付ける

<div id="modal1" role="dialog" aria-modal="true" aria-labelledby="modalTitle" hidden>
  <h2 id="modalTitle">商品の詳細</h2>
  <p>この商品の特徴は〜〜</p>
  <button type="button">閉じる</button>
</div>

エラーメッセージの通知

aria-describedby: id属性で指定したエラーメッセージと紐付ける
role=”alert”: エラーメッセージを即座に読み上げる

<label for="email">メールアドレス</label>
<input id="email" type="email" aria-describedby="errorMsg">
<p id="errorMsg" role="alert">メールアドレスを入力してください</p>

キーボード操作に対応する

マウスが使えないユーザーでもすべての機能をキーボードのみで利用できる必要があります。
フォーム入力、リンク、ボタン操作などがキーボードで操作できないと、ユーザーはページの利用自体が不可能になります。

関連するWCAG達成基準

WCAG 2.1 – 2.1.1 キーボード
WCAG 2.1 – 2.1.2 キーボードトラップなし

未対応時のユーザーへの影響

利用できなくなるユーザーがいる

身体的な理由でマウスを使用できない人、スクリーンリーダー利用者はキーボード操作が必須です。対応していないとサービスを利用できなくなります。

キーボードトラップ

キーボード利用者が特定の要素からフォーカスが抜け出せなくなることを、キーボードトラップと呼びます。
例えばモーダルを開いた後に、閉じることができなくなるとユーザーはそれ以上ページを閲覧することが不可能になります。

実装方法

EnterキーやSpaceキーで動作するようにする

デフォルトのbuttonタグやaタグはブラウザがキーボード操作に対応していますが、divタグやspanタグはそのままではキーボードで操作できません。
やむを得ずdivタグやspanタグでボタンを代用する場合はrole="button"tabindex="0"を付与し、さらにkeydownイベントでキーを押した時の挙動を実装する必要があります。

role=”button”: ボタンであることを伝える
tabindex=”0″: フォーカスを可能にする。逆にフォーカスの対象から外したい場合はtabindex=”-1″を付与する

<div role="button" tabindex="0">送信</div>

コンポーネント間で一貫したナビゲーションを確保する

共通のコンポーネントをページごとにバラバラに実装すると、利用者は毎回操作方法を学び直す必要があり、混乱します。
同じ場所に同じUIが存在し、同じ操作で使えることがユーザー体験の安定につながります。

関連するWCAG達成基準

WCAG 2.1 – 3.2.3 一貫したナビゲーション
WCAG 2.1 – 3.2.4 一貫した識別性

未対応時のユーザーへの影響

操作に時間がかかる

仮にページによってメニューの位置や内容が違うと、「次はどこを探せばいいのか」と迷ってしまいます。
また、一貫性がないと学習コストが増え、操作効率も下がります。ユーザーはサイトの使い方に慣れる前に離脱する可能性があります。

意味の誤認

例えば同じ検索ボックスでも、コンポーネントによってラベルが「検索」「探す」「search」と異なると別の要素と認識してしまうことがあります。

実装方法

コンポーネントやラベルに一貫性を持たせる

グローバルナビゲーションは常にページの上部、サイドメニューは左側に統一するなど、共通コンポーネントはすべてのページで同じ位置の配置しましょう。
また、同じ役割を持つコンポーネントは同じラベルを使うことで一貫性を保ちます。

ランドマークを使う

<nav><header><main><footer>を正しく用いることで、スクリーンリーダーが「ここがナビゲーション」などとすぐに理解できます。

動的更新を伝える

コンテンツが動的に更新される場合、視覚的には変化が分かってもスクリーンリーダーには伝わらないことがあります。
そこで、ライブリージョン(aria-live属性) を利用することで変更内容をスクリーンリーダーに通知します。

関連するWCAG達成基準

WCAG 2.1 – 4.1.3 ステータスメッセージを理解する

未対応時のユーザーへの影響

更新に気づけない

例えばショッピングサイトで「カートに追加しました」と画面に表示されてもスクリーンリーダーには読み上げられない場合があります。その場合スクリーンリーダー利用者は商品追加の操作が成功したのか分かりません。

誤操作や不安につながる

フォーム送信時にエラーが発生した場合、エラーメッセージの読み上げがなければ、ユーザーは状況が分からず再送信や離脱をする可能性があります。

実装方法

aria-live を付与して更新を伝える

コンテンツが更新されたときにスクリーンリーダーに読み上げさせたい場合、その要素に aria-live属性を付与します。

<p aria-live="polite">カートに追加しました</p>
<p aria-live="assertive">メールアドレスは必須です</p>

aria-live=”polite”:現在の読み上げが終わってから読み上げる(通知や補足情報に適切)
aria-live=”assertive”:割り込んですぐに読み上げる(エラーや重要な警告に適切)
入力中に頻繁に通知すると混乱を招くため、送信時や入力欄からフォーカスを外したタイミングで通知するのが望ましいです。

roleでもそれぞれ代用することができます。
role=”status”: aria-live=”polite” と同等で、補足メッセージを伝えるのに適切。
role=”alert”: aria-live=”assertive” と同等で、エラー通知に適切。

まとめ

今回取り上げた手法は、ユーザーの操作性や理解をさらに高めるための実践的な対応です。
応用編の内容は難しく感じるかもしれませんが、どれも現場で役立つ実践的なテクニックです。
適切に組み合わせることで、より多様なユーザーに対応できます。