アクセシブルなダイアログの実装からフォーカス管理を学ぶ
前回の記事に引き続き、アクセシビリティについて書きます、Gaji-Labo でフロントエンドエンジニアをしている上條(mk-0A0)です。
前回は『APG』という ARIA の定義をもとにしたアクセシブルな UI を学べるガイドについて書きました。
APG には Patterns と呼ばれる アクセシブルな UI のパターン集があります。その中の1つであるダイアログの解説を読んだ際にフォーカス管理についての学びが多かったため、アウトプットがてら整理してみたいと思います。
また、APG は WCAG や ARIA のような規約やデザインシステムの役割は持っておらず、あくまでアクセシビリティの概念を学ぶためのものになっています。そのため紹介されている実装が絶対的な正ではないことをご了承ください。
参考:Introduction | APG | WAI | W3C
ダイアログの要件
まずは About This Pattern のセクションからダイアログの要件を改めて確認します。
参考:Dialog (Modal) Pattern | APG | WAI | W3C
- ウィンドウや他のダイアログの上に重なるウィンドウ
- 下のウィンドウは不活性になり、アクティブなダイアログから外側のコンテンツにはアクセスできない
- Tab/Shift+Tab でダイアログ内のフォーカス移動が可能
- ダイアログを閉じることなく外側へのフォーカス移動はできない
キャプチャのようなよく見る一般的な UI ですね。
余談ですが、本記事では「モーダル」ではなく「ダイアログ」というワードを使っています。この2つには違いがあるのですが、皆さんはご存知でしょうか?
「ダイアログ」は表示される要素本体(キャプチャの白背景部分)を指しているのに対し、「モーダル」はソシオメディアによると モードがある状態。つまり、システムが特定の機能の使用に制限された状態。
とされています。(参考:ソシオメディア | モーダル)
例えばダイアログが表示されている場合「モーダルなダイアログ」という表現が正確になります。(そのため「モーダルダイアログ」を「モーダル」と言うなと弊社の役員原田が言っていました)
WCAG で求められるフォーカスの挙動
ダイアログの要件はお分かりいただけたと思いますが、ではアクセシブルなフォーカスの挙動とはどういったものでしょうか?WCAG 2.2 ではフォーカスに関する項目が7つあります。その中からレベルA・AAの項目5つをピックアップしました。
- 2.4.3 フォーカス順序 (レベルA)
- 3.2.1 予測可能(フォーカス時) (レベルA)
- 1.4.13 ホバー又はフォーカスで表示されるコンテンツ (レベルAA)
- 2.4.7 フォーカスの可視化 (レベルAA)
- 2.4.11 隠されないフォーカス (最低限) (レベルAA)
参考:Web Content Accessibility Guidelines (WCAG) 2.2 (日本語訳)
最低限達成するべきであるレベルAの挙動は、操作可能なフォーカスの順序にすることとフォーカスを受け取ったときにコンテキストの変化を起こさないこととされています。「コンテキストの変化」とはフォームの送信や新しいウィンドウを開くなどの挙動を指します。
またレベルAAの中では、今回のケースの場合フォーカスの可視化が特に重要だと感じています。フォーカスはもともと可視化されていますが、それを取り除いたり outline や border で実装するのは推奨されていません。
ダイアログにおけるフォーカスの挙動
意識したいフォーカスの挙動を踏まえたうえで、APG に掲載されているダイアログの Example を見てみましょう。Example で使われるダイアログは4つあります。
Modal Dialog Example | APG | WAI | W3C
1. Add Delivery Address
Add Delivery Address ボタンを押すと表示されるダイアログです。
このダイアログの初期フォーカスは、ユーザーが最初に操作すると考えられる input の “Street” に当たります。そこから順番に後続の input、ボタンと移動し、最後のインタラクション要素である Cancel ボタンまで来たら1番最初の input(Street) に戻ります。これは「ダイアログを閉じることなく外側へのフォーカス移動はできない」というダイアログの要件を満たしており、フォーカストラップと呼ばれます。
参考:フォーカストラップとは? 〜アクセシブルなモーダル〜
そして Cancel ボタンでダイアログを閉じると、ダイアログを開いた Add Delivery Address ボタンにフォーカスが戻ります。ダイアログを閉じるなどの1つ前の状態に戻るアクションがあった時、フォーカスはそのアクションを起こした要素に戻るのが基本の挙動となります。
2. Verification Result
Add Delivery Address ダイアログの Verify Address ボタンを押すと表示されるダイアログです。
ぱっと見でお分かりかと思いますが、他のダイアログと比べてコンテンツ量が多いです。このダイアログを実際に開いた時、ボタン類は見切れて表示されていないと思います。そのため初期フォーカスが少し特殊で、一番最初のインタラクション要素であるテキストリンクではなくはじめの段落になっています。
フォーカスはインタラクション要素に付与されるのが一般的ですが、なぜこのような実装になっているのでしょうか?先ほど少し触れましたが、ボタン類はファーストビューで見切れています。その状態でボタン類に初期フォーカスを当てるとファーストビューでボタン類が表示されてしまい、逆にコンテンツ上部が見切れるためこのような手段が取られています。…といった内容がこのダイアログに書かれているので、コンテンツ量が多いダイアログのフォーカス位置とデザインの注意点について詳しく知りたい方はぜひ読んでみてください。
そして Close ボタンは Add Delivery Address ダイアログの Verify Address ボタンにフォーカスが戻ります。
3. Address Added
Add Delivery Address ダイアログの Add ボタンを押すと表示されます。
OK ボタンでダイアログを閉じると Add Delivery Address ボタンにフォーカスが戻ります。
このダイアログの場合、初期フォーカスはテキストリンクではなく OK ボタンです。順序的にはテキストリンクにフォーカスを当てるのが適切に見えますが、多くの人はリンクに飛ぶより OK ボタンでダイアログを閉じると考えられるためこのような実装になっています。
WCAG で言われている「操作可能なフォーカス順序」とは順番通りという意味ではなく、ユーザーがどういうアクションをするかという観点も含まれていそうだと感じました。
そしてリンクに飛ぶと後述する End of the Road! ダイアログが開き、閉じるとテキストリンクにフォーカスが当たった状態になります。
4. End of the Road!
Address Added ダイアログや Verification Result ダイアログなど、複数箇所からアクセスできるダイアログです。
Close ボタンでダイアログを閉じ、前のダイアログに戻ります。フォーカスは自身を開いたボタンやリンクに戻ります。
先述したとおり複数のダイアログからアクセスできるため、ダイアログを閉じてフォーカスを戻す際にどのインタラクション要素から開かれたかを取得するひと手間の工夫がされているのが分かります。
まとめ
フォーカスは気にしていましたが深い理解とまでは至ってなかったので、調べてみると想像以上に工夫できることがたくさんあって学びが多かったです。文中でフォーカストラップについて少し触れましたが、調べる過程で「キーボードトラップ」と混ざってしまい混乱していました。ちなみにキーボードトラップとは、例えばダイアログの閉じるボタンにフォーカスが当たらないことでキーボード操作ではダイアログを閉じられず、閉じるにはマウスしか使えないという状態だそうです。(参考:達成基準 2.1.2: キーボードトラップなしを理解する)
今回キーボードトラップについて文中では触れませんでしたが、キーボードトラップをしないことはレベルAに設定されているので、より一層意識して不注意によってアクセシビリティを損なわないように気をつけなければと思いました。
Gaji-Labo はアクセシビリティの知見がある・アクセシビリティに興味があるエンジニア、デザイナーの方とお話できる機会を作りたいと思っています。興味のある方、ぜひカジュアル面談でお話ししましょう!
Gaji-Labo フロントエンドエンジニア向けご案内資料
Gaji-Labo は Next.js 開発の実績と知見があります
フロントエンド開発の専門家である私たちが御社の開発チームに入ることで、バックエンドも含めた全体の開発効率が上がります。
「既存のサイトを Next.js に移行したい」
「人手が足りず信頼できるエンジニアを探している」
「自分たちで手を付けてみたがいまいち上手くいかない」
フロントエンド開発に関わるお困りごとがあれば、まずは一度お気軽に Gaji-Labo にご相談ください。
オンラインでのヒアリングとフルリモートでのプロセス支援にも対応しています。
フロントエンドの相談をする!