こんにちは。アイレット株式会社デザイン事業部の上瀧です。
今回は最近モダンブラウザにサポートされた :modal擬似クラスについて調べてみました。

私⾃⾝がこれまでモーダルのHTML/CSS実装について苦戦することが多かったため、本記事で
は、 :modal擬似クラスを使うことによってその悩みが解決できそうかを検証していきたいと思います。

:modal 擬似クラスとは

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

  1. JavaScriptの showModal() によって表⽰されるdialog要素
  2. JavaScriptの requestFullscreen() によって表⽰されるフルスクリーン要素

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

Can I use より

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

基本的な使い⽅

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

See the Pen
codepen-modal-01
by iret-jotaki (@iret-jotaki)
on CodePen.

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

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

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

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

:modal のスタイル調整

#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指定が必要になりそうかを⾒ていきます。

See the Pen
codepen-modal-02
by iret-jotaki (@iret-jotaki)
on CodePen.

#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を必要とせずに意図通りにレイヤーが構成されています。

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

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

See the Pen
codepen-modal-03
by iret-jotaki (@iret-jotaki)
on CodePen.

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

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

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

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

フェードイン・アウトで表⽰・⾮表⽰

デフォルトCSSの場合は瞬時にモーダルが表⽰・⾮表⽰されるため、フェードイン・アウトのアニメーショ
ンを付与できるかを検証します。
結果、 :modal に対しては transition を指定した場合もアニメーションは動作しませんでした。
そこで多少強引な部分もありますが、JavaScriptでクラスを付け替えしつつ、@keyframesを⽤いた
CSSアニメーションでフェードイン・アウトを実現することはできました。

See the Pen
codepen-modal-04
by iret-jotaki (@iret-jotaki)
on CodePen.

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

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

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

See the Pen
codepen-modal-05
by iret-jotaki (@iret-jotaki)
on CodePen.

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

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

まとめ

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

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

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