:modal 擬似クラスを試してみた

:modal 擬似クラスとは

MDNでは、下記のように説明されています。

  1. JavaScriptshowModal() によって表示される dialog 要素
  2. JavaScriptrequestFullscreen() によって表示されるフルスクリーン要素

先日リリースされたChrome 105、Edge 105でSafariFirefoxを含めた主要ブラウザにサポートされる擬似クラスとなりました。

Can I use より

この記事では、業務で使用する頻度が高そうな 1. の showModal() によって表示される dialog 要素 について検証を行いました。

基本的な使い方

まず、シンプルに「モーダルを開く」ボタンを押すとモーダルが表示され、「モーダルを閉じる」ボタンを押すとモーダルが非表示になる例を見ていきます。

簡単な例にはなりますが、3点のポイントを解説します。

モーダルは <dialog> 要素でマークアップする

<dialog>
  <!-- モーダルの中身です -->
</dialog>

ボタン押下後に表示されるモーダルは <dialog> 要素でマークアップをします。

#my-modal:modal {
  /* モーダルのボックス自体 */
}
#my-modal::backdrop {
  /* モーダル後ろの背景レイヤー */
}

CSSセレクターとしての :modal は、モーダルのボックス自体、::backdrop はモーダル背景レイヤーのスタイル指定となります。

JavaScriptで表示制御を行う

const modal = document.querySelector('#my-modal')
const buttonOpen = document.querySelector('#button-open')
const buttonClose = document.querySelector('#button-close')

buttonOpen.addEventListener('click', () => {
  modal.showModal() // 表示
})

buttonClose.addEventListener('click', () => {
  modal.close() // 非表示
})

それぞれのボタンをクリックして、showModal() で表示、close() で非表示するようにします。

デザイン観点での検証

過去にモーダルのデザイン調整では次のような悩みがあったため、:modal 擬似クラスでは解消できるのかを検証します。

  • モーダルと背景レイヤーのスタイル調整
  • コンテンツ量が多い場合のボックス位置
  • フェードイン・アウトで表示・非表示
  • スマートフォンでの背景コンテンツがスクロールしてしまう件

※ 本記事執筆時点の Mac/Chrome、もしくは iOS/Safari の環境で再現した内容になります。

モーダルと背景レイヤーのスタイル調整

まずはモーダルと背景レイヤーに対してどのようなCSS指定が必要になりそうかを見ていきます。

#my-modal:modal {
  padding: 2.5rem;
  border: 0;
  border-radius: .5rem;
  background-color: #fff;
  box-shadow: 0 0 2rem .5rem rgba(0,0,0,.1);
}
#my-modal::backdrop {
  background-color: rgba(255,255,255,.8);
}

/* 以降省略 */

CodePenでのサンプル通り、モーダルのボックス自体へ枠線、角丸、背景色、影の指定が再現されました。
背景についても ::backdrop 疑似要素がブラウザのデフォルトで固定配置( position: fixed )となっているため、背景色の指定のみで基本は問題なさそうです。

重なり順についても z-index を必要とせずに意図通りにレイヤーが構成されています。

コンテンツ量が多い場合のボックス位置

モーダルの中のコンテンツ量が多い場合、どのような挙動になるでしょうか。

ブラウザのデフォルトCSSでは、モーダルはコンテンツ量に応じてなりゆきで可変しますが、例えば CodePenのサンプルのように max-widthmax-height

#my-modal:modal {
  max-width: 50vw;
  max-height: 50vh;
}

と指定すると、モーダル外のマージンを保ち中央に配置されつつ、全体の横幅や高さが短い場合でもスクロールバーが表示されました。

ただ細かい点にはなりますが、モーダルコンテンツ内がスクロールするサイズで表示された際、スクロール位置が最下部に来てしまうようなので、気にすべきポイントではある印象です。

フェードイン・アウトで表示・非表示

デフォルトCSSの場合は瞬時にモーダルが表示・非表示されるため、フェードイン・アウトのアニメーションを付与できるかを検証します。

結果、:modal に対しては transition を指定した場合もアニメーションは動作しませんでした。

そこで多少強引な部分もありますが、JavaScriptでクラスを付け替えしつつ、@keyframes を用いたCSSアニメーションでフェードイン・アウトを実現することはできました。

参考記事: dialog with animation by geckotang on CodePen

スマートフォンでの背景コンテンツがスクロールしてしまう件

スマートフォン端末で意図せず背景コンテンツがスクロールしてしまう現象は :modal 擬似クラスでは解消できるのでしょうか。

コンテンツのエリアの高さを取った上でモーダルを表示したところ、背景コンテンツもスクロールしてしまいCSSでは解消できませんでした。

現時点ではモーダル表示時にbody要素を position: fixed にするなど従来通りJavaScriptを含めた対策が必要そうです。

まとめ

:modal 擬似クラスについて、主にデザインの観点から再現できること、できないことを検証しました。

個人的には思っていたよりも再現できることも多く、JavaScriptでの指定なしでEscキーでモーダルを閉じることができるなど他のメリットも多い印象でした。

記事内で再現が難しかった事項とのトレードオフにはなりますが、実際のプロジェクトでも要件によって使用の検討をして良いのかなという感触を得られました。