【実務・中級編】 :modal モーダル疑似クラス – CSS実践ガイド

やあ、現場で日々CSSの仕様変更やブラウザの挙動と戦っている戦友諸君。調子はどうだい?

今日は、私たちが長年苦しめられてきた「モーダル実装」という名の呪縛から、ついに我々を解き放ってくれる強力な武器——`:modal` 疑似クラスについて語ろうと思う。

かつてのモーダル実装といえば、どうだった? `z-index: 9999` を指定し、それでも重なり順が解決せずに親要素の `overflow: hidden` に泣かされ、背景を固定するために body にクラスを付け外しする……。そんな「泥臭いハック」の時代は、もう終わりだ。

モダンブラウザが標準で提供する `

` 要素と、それを制御する `:modal` 疑似クラスの真髄を、現場目線で徹底的に解説していくぞ。

—

1. なぜ今、`:modal` なのか?

これまで、モーダルが開いているかどうかをCSSで判定するには、JavaScriptでクラスを付与するか、属性セレクタ `[open]` を使うのが一般的だった。

しかし、HTMLの `

` 要素には2つの開き方があるのを知っているかな?
1. `dialog.show()`:ただ表示されるだけ(非モーダル)
2. `dialog.showModal()`:背後へのインタラクションを遮断する(モーダル)

ここで登場するのが `:modal` 疑似クラスだ。
このセレクタは、「`showModal()` メソッドによって開かれ、ブラウザの『トップレイヤー』に配置された状態」の要素だけをピンポイントで射抜く。

単なる表示状態ではなく、「ユーザーの操作を独占している特別な状態」をCSSが直接認識できるようになった。これは、宣言的UIを好む我々フロントエンド・エンジニアにとって、極めて大きな進化なんだ。

—

2. ブラウザの裏側:最強の聖域「Top Layer」

`:modal` を理解する上で、ブラウザの内部的な仕組みである 「トップレイヤー(Top Layer)」 について触れないわけにはいかない。

通常、要素の重なり順は `z-index` やスタックコンテキスト(重ね合わせ文脈)に支配される。だが、`showModal()` で呼び出された要素は、DOMツリーの構造を無視して、ブラウザが管理する「最前面のレイヤー」へと強制的にワープする。

このトップレイヤーこそが、`z-index: 9999` 同士の不毛な争いを終わらせる聖域だ。
そして、`:modal` はその聖域に鎮座している要素を識別するための専用の鍵だと思えばいい。

—

3. 実践:`:modal` と `::backdrop` の黄金パターン

では、実際に現場ですぐに使えるコードを見ていこう。
ポイントは、`:modal` 状態のときだけ適用したいスタイルと、モーダルの背景(オーバーレイ)を制御する `::backdrop` 疑似要素との組み合わせだ。


/ ————————————————–

  • 1. 基本のダイアログスタイル
  • ————————————————– /

dialog {
border: none;
border-radius: 12px;
padding: 0;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
width: 400px;
max-width: 90vw;
/

  • dialog自体は最初から display: none 的な挙動をするが、
  • ここでは基本的な見た目だけを定義しておく。

/
}

/ ————————————————–

  • 2. :modal 疑似クラスの活用
  • showModal() で開かれた時だけ特別なスタイルを当てる
  • ————————————————– /

dialog:modal {
border: 2px solid #007bff; / モーダル時だけ枠線を強調 /
animation: fadeIn 0.4s ease-out; / ふわっと表示させる /
}

/ ————————————————–

  • 3. ::backdrop で背景をデザインする
  • :modal とセットで使うのが実務の鉄板だ
  • ————————————————– /

dialog::backdrop {
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px); / 背景をぼかすモダンな演出 /
}

/ アニメーションの定義 /
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

/ フォーム内のレイアウト調整 /
.modal-content {
padding: 24px;
}

// JavaScript側の制御もこれだけだ
const modal = document.getElementById(‘myModal’);
const btn = document.getElementById(‘openBtn’);

btn.addEventListener(‘click’, () => {
// show() ではなく showModal() を使うのが重要!
// これにより、CSSの :modal セレクタが反応するようになる。
modal.showModal();
});

—

4. 現場のシニアが教える「ここが落とし穴」

`:modal` を使いこなすために、君たちにいくつかアドバイスしておこう。

「開いている」と「モーダルである」は別物だ

`dialog[open]` というセレクタも存在するが、これは `show()` で開いた「ただのポップアップ」にも反応してしまう。
一方、`:modal` は 「背後の操作をロックしている状態」 を厳格に区別する。アクセシビリティ(A11y)の観点からも、キーボードの Tab キー移動がダイアログ内に閉じ込められる(Focus Trapping)のは、この `:modal` 状態のときだけだ。

背景(::backdrop)の継承に注意

`::backdrop` は `

` の子要素ではない。DOMツリー上では隣接もしていない特殊な要素だ。
そのため、親要素の CSS 変数(Custom Properties)を継承できない場合がある。もし背景の色を動的に変えたいなら、`:root` で変数を定義するか、直接指定する必要がある。ここはハマりやすいポイントだ。

互換性とプログレッシブ・エンハンスメント

現在、主要なモダンブラウザ(Chrome, Edge, Firefox, Safari)はすべて `:modal` をサポートしている。
だが、古い環境をどうしても考慮しなければならない場合は、`dialog:modal` が効かない前提のフォールバックを軽く書いておくといい。とはいえ、もう 2024 年だ。そろそろ「標準の力」を信じて突き進んでもいい頃合いだろう。

—

結び:CSSの進化を楽しもう

かつて JavaScript で 100 行書いていた制御が、今や CSS の疑似クラス一つでスマートに解決できる。
`:modal` 疑似クラスの使用は、単なるコードの短縮ではない。ブラウザが持つ「状態管理」のネイティブな機能を正しく使い、アクセシビリティとパフォーマンスを両立させるという、プロフェッショナルな設計思想の現れなんだ。

次にモーダルを実装する機会があったら、ぜひこの `:modal` を使ってみてくれ。
「ああ、z-index と格闘していたあの日々は何だったんだ」と、きっと君も膝を打つはずだ。

またフロントエンドの深淵で会おう。健闘を祈る!

コメント

タイトルとURLをコピーしました