モーダルウィンドウは、タップやクリックで表示されるウィンドウ(窓)のことです。
モーダルダイアログとも呼ばれ、ユーザーがそのウィンドウを閉じるまで他の操作ができないように制御される点が特徴です。
背景が暗くなることが多く、ユーザーの集中を特定のコンテンツやアクションに向けさせる目的があります。
たとえば、ポップアップやアラートメッセージ、確認ダイアログなどがモーダルウィンドウに該当します。
今回はこのモーダルウィンドウの実装をします。アクセシビリティやユーザー体験を考慮しながら、ベストプラクティスの方法を解説しますので、ぜひ最後までお付き合いください。
HTMLの記述
まずはHTMLを記述します。
<button class="modalOpen">open</button>
<dialog class="modal">
modal text
<button class="modalClose">close</button>
</dialog>
一行目はmodalOpenクラスをつけたボタンです。このボタンをクリックするとモーダルウィンドウが開くようにします。
その下にはdialogタグを書いています。このタグの中に記述する内容がモーダルウィンドウの中身です。
dialogタグについて
dialogタグは、HTML5の仕様として組み込まれているモーダルウィンドウ用のタグです。デフォルトで非表示となっており、以下のメソッドで制御されます。
showModal() : このメソッドを使うと、 要素がモーダルウィンドウとして表示され、他のコンテンツを操作できなくなります。自動的に最前面に表示されるため、z-index の指定は不要です。また、オーバーレイが生成され、ユーザーはウィンドウを閉じるまで背景の操作ができません。
close() : このメソッドで 要素が閉じられ、ウィンドウは非表示になります。閉じるときのデフォルトの動作も実装されています。
他のタグでも実装できますが、アクセシビリティを意識するならdialogタグを使うのがおすすめです。
JavaScriptの記述
次はJavaScriptの記述をします。まずはモーダルウィンドウを開く実装です。
const modals = document.querySelectorAll(".modal");
const modalOpens = document.querySelectorAll(".modalOpen");
modalOpens.forEach((open, index) => {
open.addEventListener("click", () => {
const modal = modals[index];
if (modal) {
modal.showModal();
document.documentElement.style.overflow = "hidden";
}
});
});
モーダルウィンドウが複数あることを想定して、querySelectorAllで要素を取得しています。
まずはopenボタン要素を取得し、それぞれの要素に対してクリックした時の処理を書いています。modals[index]で、ボタンとモーダルの順番を合わせているため、最初のボタンを押すと最初のモーダルが開くといったことが可能になっています。
modal.showModal();は先ほど紹介したメソッドです。これだけでモーダルやオーバーレイが表示されるため、非常に便利です。
その下の行ではhtml要素に対してoverflow=”hidden”を付与しています。これによりモーダルウィンドウが開いた時に、オーバーレイの下のスクロールを止めています。モーダルウィンドウが開いている時に知らずにスクロールしていて、ウィンドウを閉じたら、「全然知らない場所にいた」などといったことを防ぐためです。
では、同じようにクローズの方も記述していきます。
modalCloses.forEach((close, index) => {
close.addEventListener("click", () => {
const modal = modals[index];
if (modal) {
modal.close();
document.documentElement.removeAttribute("style");
}
});
});
オープンとほとんど同じですね。modal.close();でモーダルウィンドウを閉じるメソッドを使っており、その下では、スクロールを止めていたスタイルを削除しています。
これだけでもいいのですが、わざわざクローズボタンを押さなくても背景(オーバーレイ)を押せばウィンドウが閉じるようにします。ユーザーに寄り添った実装ですね。
modals.forEach((modal) => {
modal.addEventListener("click", (event) => {
const rect = modal.getBoundingClientRect();
if (
event.clientX < rect.left ||
event.clientX > rect.right ||
event.clientY < rect.top ||
event.clientY > rect.bottom
) {
modal.close();
document.documentElement.removeAttribute("style");
}
});
});
今回はmodalをクリックした場合という設定です。ただ、そのままだと開いたウィンドウをクリックしてもモーダルが閉じてしまうので、要素の外側をクリックした場合といった実装をします。
ポイントとなるのは、getBoundingClientRect()関数です。これはJavaScriptのメソッドで、要素の位置やサイズを計測するために使用します。今回のケースでは、これでモーダルの外側のすべての値を取得しています。
event.clientXとevent.clientYは、クリックする位置を取得しています。
これらを組み合わせることにより、モーダルの外側をクリックした場合はモーダルを閉じるといった処理を実装しています。
完成版
ここまで実装したものにCSSを当て、少し調整すると、以下のようになります。
See the Pen modalWindow by Bunta (@bbunta) on CodePen.
ポイントはHTMLのaria-labelの記述です。
先ほどのHTMLとは違い、オープンボタンの名前を「ボタン1」としたため、スクリーンリーダー(音声読み上げソフト)を使用している方が、何のボタンか分からため、aria-labelで「モーダルウィンドウを開く」と記述しています。
同じくクローズボタンはCSSの擬似要素でバツを作っているため、スクリーンリーダーで「モーダルウィンドウを閉じる」と読んでもらえるように記述しています。
モーダルウィンドウを開いた時に、オーバーレイの下がスクロールできないことを確認できるように、高さは200vhにしています。
まとめ
今回はアクセシビリティとユーザー体験を考慮したモーダルウィンドウの実装の解説をしました。
アクセシビリティ対応は直接的なSEO要因ではありませんが、ユーザー体験の向上を通じて検索エンジンから評価されやすくなります。
少し手間はかかりますが、プロとして仕事をする場合は、見えないところまで気を配り、アクセシビリティに配慮したコーディングをするようにしましょう。
以前書いた以下の記事でも、アクセシビリティに配慮した実装方法を紹介しています。ぜひ参考にしてみてください。
アコーディオンメニューの実装(JavaScriptありorなし)