Step 1: Web Basics
07. モーダル画面を作る時の
z-index の罠
iPhoneユーザー向けの「保存ガイド」を作っていた時のこと。画面全体を覆うはずの黒いオーバーレイを突き抜けて、背後にあるボタンが「こんにちは」をしてくる怪奇現象に遭遇しました。Webデザインにおける「奥行き」の管理は、思った以上にロジカルで奥が深いものでした。
1. Webページにある「見えない奥行き」
Webページはブラウザに表示される平面的なものですが、CSSには Z軸(奥行き) という概念が存在します。この重なり順を制御するのが z-index プロパティです。
通常、HTML要素はコードの後に書かれたものほど手前に表示されますが、モーダルやドロップダウンメニューのように「強制的に一番手前に持ってきたい」要素がある場合、この z-index を使ってレイヤーの順序を明示的に指定する必要があります。
2. 数値が大きければ良い、というわけではない?
初心者がやりがちなのが、要素が手前に来ないからといって z-index: 9999; のように適当に大きな数字を設定することです。しかし、これでも解決しない場合があります。
実は z-index が有効になるには、その要素の position プロパティが static(初期値)以外である必要があります。つまり、relative, absolute, fixed, sticky のいずれかが設定されていないと、いくら数値を大きくしても無視されてしまうのです。
Tailwind CSS でのレイヤー管理例
「猫の手ツール」では Tailwind CSS を採用しているため、以下のように階層構造を整理しています。
【正解】オーバーレイとモーダルの関係
<!-- 背後の半透明カバー (z-40) -->
<div class="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-40"></div>
<!-- モーダルコンテンツ (z-50) -->
<div class="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 bg-white rounded-2xl p-8">
<h3>画像を保存する方法</h3>
<p>画像を長押しして「写真に保存」を選択してください。</p>
</div> 3. 最大の落とし穴「スタッキング文脈」
今回の開発で一番苦戦したのが スタッキング文脈(重なりコンテキスト) という概念です。
これは、ある要素が「新しいレイヤーの親」になってしまう仕組みです。例えば、親要素Aに opacity: 0.9 や transform が設定されていると、その中の子要素Bにどれだけ大きな z-index を設定しても、親要素Aのレイヤーの枠組みを超えて手前に出ることはできません。
インフラのネットワーク階層(OSI参照モデル)に例えると、第2層(データリンク層)の中でいくら優先順位を上げても、第3層(ネットワーク層)の制御を飛び越えて通信できないのと似ています。常に「今どの階層(コンテキスト)で話をしているのか」を意識しなければなりません。
4. 注意点:z-index の管理を破綻させないコツ
大規模な開発になるほど、z-index の数値はカオスになりがちです。以下のルールを守ることで、管理が劇的に楽になります。
- 1刻みで使わない: Tailwind のように 10, 20, 30... と間隔をあけて定義する。
- 変数の活用:
z-modal,z-overlay,z-headerのように役割で名前をつける。 - DOMの位置: モーダル要素などは、可能な限り
<body>の直下など、階層の浅い場所に配置する(スタッキング文脈の影響を最小限にするため)。
5. まとめ:実務での役立ち
「猫の手ツール」では、iPhoneユーザー向けの保存ダイアログや、サイドメニューの表示にこの z-index の設計を活かしています。
見た目にはただ重なっているだけの要素も、その裏側には厳格な優先順位が存在します。目に見えない順序をロジカルに整理すること。それが、ユーザーにとって違和感のない、スムーズなUI/UXを提供するための第一歩なのだと改めて実感しました。