モーダルウィンドウのコンテナ要素に aria-modal 属性を適用する
先の記事「折り畳まれたナビゲーションメニューの展開 (オーバーレイではなくインレイで)」を書く過程で、オーバーレイで提示されるモーダルウィンドウのアクセシビリティについて改めて調べていたところ、aria-modal
という属性が気になりました。aria-modal
とは、2017年に勧告された WAI-ARIA 1.1 から追加されたプロパティで、あるコンテナ要素に aria-modal="true"
という属性が適用されている場合、その要素がモーダルであることをスクリーンリーダーなどの支援技術に示し、それ以外のコンテンツの利用を排除する (インタラクション可能な範囲を、モーダルのコンテンツに限定する) というものです。(参考 : aria-modal の定義 (WAI-ARIA 1.1) / 日本語訳)
従来、モーダルウィンドウを (スクリーンリーダーおよびキーボード操作に依存するユーザーにとって) アクセシブルなものにするには、以下の実装が必要です。
- JavaScript を用いて、[Tab] キーによるフォーカス移動を展開中のモーダルウィンドウ内に限定する。併せて、[Esc] キーで展開中のモーダルウィンドウを閉じるようにする。
- モーダルウィンドウのコンテナ要素に
role="dialog"
を適用し、スクリーンリーダーを介してダイアログが開いた旨をユーザーに伝える。 - モーダルウィンドウのコンテナ要素に
aria-labelledby
やaria-describedby
を適用し、モーダルウィンドウ内の見出しや説明文などが、モーダルウィンドウ展開時に即座にスクリーンリーダーで読み上げられるようにする。 - モーダルウィンドウの展開中は、背景側の元ページのコンテンツ要素に
aria-hidden= "true"
を適用し、不意にスクリーンリーダーでアクセスされてしまうことを防ぐ。
上の箇条書きのうち、特に厄介なのは、いちばん下の項目 (モーダルウィンドウ展開中に、それ以外のコンテンツ要素に aria-hidden= "true"
を適用すること) です。ところが、モーダルウィンドウのコンテナ要素に aria-modal="true"
を適用すれば、仕様上、それ以外の要素に aria-hidden
を適用することを省くことができるので、実装がとても楽になることが期待できます。(参考 : WAI-ARIA Practices 1.1 Authoring Practices「3.9 Dialog (Modal)」 / 日本語訳)
この aria-modal
、実際にスクリーンリーダーで利用したときの挙動はどうなのか、試してみたいと思い、Bootstrap を用いて CodePen にて簡単なデモを作ってみました (Full Page View はこちら)。
See the Pen アクセシブルなモーダルウィンドウ by @caztcha (@caztcha) on CodePen.
aria-modal
の有効性を検証するために、敢えてモーダルウィンドウのコンテナ要素の外側に、見出し、リンク、ランドマーク (メインコンテンツを示す role="main"
とフッターを示す role=contentinfo
) を置いてあります。モーダルウィンドウを開くと、モーダルウィンドウのコンテナ要素に対して、role="dialog"
と aria-modal="true"
が動的に適用されます (これは Bootstrap の Modal コンポーネントの標準的な挙動です)。ブラウザの開発者ツールで見ると、下図のように動的に属性が適用されているのがわかります。
モーダルウィンドウが開いた状態で、[Tab] キー (または [Shift] + [Tab]) を押すと、フォーカス移動はモーダルウィンドウ内に限定されます。スクリーンリーダーで読み上げ対象を前後に動かしても、同様に、読み上げ対象はモーダルウィンドウ内に限定されます。この状態で、スクリーンリーダーの機能を用いて、見出し、ランドマーク、リンクへのジャンプをしようとしても、aria-modal
が効いて、モーダルウィンドウの外側には読み上げ対象が移動しません。以下のユーザーエージェントの組み合わせで、このような期待通りの挙動になることを確認しました。
- Windows 10 : NVDA + Chrome (90.0) / Firefox (88.0) / Edge (90.0)
- macOS (11.4) : VoiceOver + Safari (14.1) / Chrome (90.0)
- iOS (14.6): VoiceOver + Safari (14.1) / Chrome (90.0)
role="dialog"
のみでも (aria-modal
がなくても) モーダルウィンドウの外側に読み上げ対象が移動しないようになっています。
Accessibility Support (a11ysupport.io) の「aria-modal attribute (aria)」セクションを見ると、VoiceOver (iOS、Mac ともに) では未対応なところがある ("none" または "partial" という判定) となっていますが、現時点で試した感じでは、実質的には問題ないかな、と感じました。
ただ残念ながら、Android の TalkBack では、この aria-modal
はうまく機能しないようです。上述の Accessibility Support (「aria-modal attribute (aria)」セクション) でも TalkBack の対応は壊滅状態 (軒並み "none" 判定) ですが、私自身、実際に TalkBack 9.1 で試したところ、やはりダメでした。広くアクセシビリティを担保するために現時点では念のため併せて、モーダルウィンドウの展開中は、それ以外の背景側のコンテンツ要素に aria-hidden= "true"
を適用するのが無難と言えそうです。(TalkBack 側の今後のアップデートに期待したいところです。)