モーダルウィンドウを考える

ウェブサイトのユーザーインターフェース (UI) に、「モーダルウィンドウ」と呼ばれるものがあります。ページ遷移を伴わずに、ページ上にウィンドウをオーバーレイ表示させるもので、このウィンドウが前面で開いている間は背景側にある元ページが操作対象外になることから「モーダル」という名称が付いています。実装例としては、フォーム、アラート、画像の拡大表示 (いわゆる Lightbox 系と呼ばれるもの) などが挙げられます。

モーダルウィンドウは、あるページを開いているというコンテキストを維持しつつ付加的にコンテンツの提示ができる利点がある反面、基本的なユーザビリティやアクセシビリティが欠落しているケースが多く見受けられます。以下の観点を意識しながらデザインや実装をすることで、基本的なユーザビリティやアクセシビリティを損なわないようにしたいものです。

「モーダルウィンドウであること」をユーザーに認知させる

モーダルウィンドウは、ウェブサイトにおける一般的なコンテンツ表示の変化 (ページ遷移) とは異なる特殊なインタラクションであるため、ユーザーが「モーダルウィンドウであること」を認知できるようにデザインすることが大事です。つまり、コンテンツ表示は変化しても元ページは背景側に残っていること (ページが切り替わったわけではないこと)、今開いてるコンテンツはその上に重なって (オーバーレイする形で) 表示されていること、また用が済んだらオーバーレイ表示されているコンテンツを閉じて背景側にある元ページを再びアクティブにする (前面に出す) こと、をデザインによって明示的にするのです。たとえば、以下によって表現します。

モーダルウィンドウの領域が視覚的に不明瞭な例。背景のあしらいやクローズボタンの配置が不適切なため「ゲシュタルト崩壊」を起こしている。フラットデザインの流行の影響か、このようなデザインを時折見かける。
モーダルウィンドウの領域が視覚的に不明瞭な例。

モーダルウィンドウのユーザビリティ問題でよく見られるのが、ブラウザの「戻る」ボタンを押してしまい、ユーザーの予測と異なったページに戻ってしまうことです。モーダルウィンドウのインタラクション概念がユーザーのメンタルモデルとして形成されていないがために、一般的なページ遷移との混同が生じてしまうのです。上記に挙げたデザイン上の工夫によってモーダルウィンドウの概念をユーザーに植え付けることで、ユーザーのミステーク (誤解による誤操作) をできるだけ防止したいものです。

モーダルウィンドウを開いた状態でブラウザの「戻る」ボタンを押すと、ユーザーの予測と異なったページに戻ってしまう。デザインによってこのミステークをなるべく防止したい。
モーダルウィンドウを開いた状態でブラウザの「戻る」ボタンを押すと、ユーザーの予測と異なったページに戻ってしまう。

なお、フールプルーフの一手法として、モーダルウィンドウが開いた状態に対し pjax で個別 URL を割り当てる (ブラウザの「戻る」ボタンを押すとモーダルウィンドウが閉じて背景側の元ページに戻る) ことも可能ですが、それはそれで、ユーザーのメンタルモデルに合致しないケースが出てきたり、ブラウザの履歴に残ることでかえって煩わしい挙動になったり、モーダルウィンドウが開いた状態に直接ランディングされてユーザーを混乱させたり、といった恐れもあるので慎重に検討したいところです。

キーボード操作を担保する

基本的なアクセシビリティ担保の一環として、モーダルウィンドウはキーボード操作で利用できるようにしておくことが大事です。その際の主な要件としては、以下が挙げられます。

スクリーンリーダーでも利用できるようにする

もうひとつ重要なアクセシビリティ担保として、モーダルウィンドウは視覚障害者 (スクリーンリーダーユーザー) も利用できるようにすることが大事です。主な要件として、以下が挙げられます。

モーダルウィンドウが開いた旨の通知

モーダルウィンドウを括るコンテナ要素 (<div> など) に role= "dialog" を記述しておくと、モーダルウィンドウが開くと同時に、一部のスクリーンリーダー (Windows の NVDA、OS X の VoiceOver など) は「ダイアログ」と音声で知らせてくれます (iOS の VoiceOver や Android の TalkBack では、このような音声通知はまだ無いようです)。なお、モーダルウィンドウがアラートメッセージである場合は、代わりに role= "alertdialog" と記述するべきです (そうすることで、たとえば OS X の VoiceOver は「警告ダイアログ」と知らせてくれます)。

ところで、role= "dialog" を「ダイアログ」と音声通知しないスクリーンリーダーでも、role= "dialog" を記述したコンテナ要素に aria-labelledby や aria-describedby を記述しておく (モーダルウィンドウ内の見出し要素や概要文の要素と id 属性値を介して紐づけておく) ことで、モーダルウィンドウが開くと同時に見出しや概要文を音声読み上げしてくれるので、それによってスクリーンリーダーユーザーは文脈的に、モーダルウィンドウが開いたことを認識することは可能です。

モーダルウィンドウの中身の読み上げ

スクリーンリーダーによっては、role= "dialog" のモーダルウィンドウが開くと「フォーカスモード」に切り替わってしまい、フォーカス可能要素 (フォーム入力要素やボタンなど) しか読み上げない場合があります。文章が書いてあるモーダルウィンドウなど、フォーカス可能要素以外も読み上げ対象にしたい場合は、スクリーンリーダーを「ブラウズモード」にする必要があります。

そのための裏技として、role= "dialog" を記述したコンテナ要素の内側 にある (実質的にモーダルウィンドウのコンテンツを括っている) 要素に対して role= "document" を記述するというテクニックがあります。こうすることで、モーダルウィンドウが開いた後に [Tab] キーを押すと、role= "document" が記述された要素にフォーカスが当たり、同時にスクリーンリーダーは自動的にブラウズモードに切り替わります。

クローズボタンの代替テキスト

モーダルウィンドウのクローズボタンは多くの場合、視覚的には「×」のアイコンのみが表示されることでしょう。可能であれば「閉じる」といったテキストラベルもボタン内に併記したいところですが、それが難しい場合は、スクリーンリーダーユーザーに対して「モーダルウィンドウを閉じるボタンである」旨を伝えるために、<button> 要素の中で aria-label を用いて具体的な代替テキストを記述しましょう。

読み上げ対象の限定 (モーダルウィンドウのみを読み上げる)

モーダルウィンドウが開いた状態では、スクリーンリーダーによる音声読上げの対象はモーダルウィンドウのみに限定されるべきです。モーダルウィンドウを開いたまま背景側の元ページの内容が読み上げられてはいけません。

モーダルウィンドウを括るコンテナ要素に role= "dialog" を記述しておくことで、自動的に読み上げ対象をモーダルウィンドウ内に限定してくれるスクリーンリーダーもありますが、キーコマンドを実行したときに (たとえば [H] キーを押して見出しのみを拾い読みしようとしたときに) 読み上げ対象のフォーカスが背景側の元ページに移動してしまう場合もあります (私の手元の検証環境では OS X VoiceOver がそうでした)。

これに対する解決策としては、モーダルウィンドウを括るコンテナ要素に aria-modal="true" も併せて記述し、そのうえで念のため、モーダルウィンドウが開いている間は背景側の元ページのコンテンツ要素を aria-hidden= "true" に切り替えるようにするとよいでしょう。


以上を意識することで、モーダルウィンドウの基本的なユーザビリティやアクセシビリティをある程度保つことができると思います。そもそもモーダルウィンドウは、ウェブサイトにおける一般的なコンテンツ表示の変化 (ページ遷移) とは異なる特殊なインタラクションなので安易な採用はおすすめしませんが、実装する必要がある場合は、ご参考になれば幸いです。