ビューポートクリッピングで z-index が効いてくれない

# 1. はじめに
web 開発をしていて、ドロップダウンメニューが親要素の境界によって見切れるという状況が発生しました。
ここで、悪さをしていたのは、`overflow` プロパティでした。

この記事では、この問題の背景を掘り下げ、なぜ `overflow` プロパティがドロップダウンメニューの表示に影響を与えるのかについて扱います。

# 2. 基本概念の解説
必要な基本概念を整理します。
## `overflow` プロパティ
overflow プロパティは、要素のコンテンツがそのコンテナの境界を超えた場合にどのように扱うかを定義します。主に以下の値があります：

`visible`：コンテンツが境界を超えても切り取られずに表示される。
`hidden`：境界を超えるコンテンツは表示されずに隠れる。
`scroll`：コンテンツが境界を超えるとスクロールバーが表示される。
`auto`：必要に応じてスクロールバーが表示される。
このプロパティは通常、コンテンツの整理とアクセス性向上のために使用されますが、特定の状況では副作用が生じる可能性があります。

## ブロック整形コンテキスト（BFC）
ブロック整形コンテキストは、Webページの一部で、その中の要素のレイアウトがどのように行われるかを決定する規則の集まりです。BFCは以下のような場合に形成されます：

`overflow` プロパティが `visible` 以外の値に設定されている要素。
`float` プロパティが `none` 以外の値に設定されている要素。
`display` プロパティが `inline-block`, `table-cell`, `table-caption`, `flex`, `grid` などに設定されている要素。
`position` プロパティが `absolute` や `fixed` に設定されている要素。
BFCは、その内部でのマージンの折り返しやフローティング要素の影響を受けない独立した領域を作ります。

## スタッキングコンテキスト
スタッキングコンテキストは、要素の重ね合わせ順序を制御する環境です。z-index プロパティは、スタッキングコンテキスト内でのみ機能します。スタッキングコンテキストは、以下のような場合に形成されます：

- `position` プロパティが `relative`, `absolute`, `fixed` または `sticky` で、かつ `z-index` の値が `auto` でない要素。
- CSSの特定のプロパティ（`opacity`, `transform`, `filter`, `perspective`, `clip-path`, `mask`, `contain`, `will-change` など）が適用されている要素。

スタッキングコンテキストの形成は、ドロップダウンメニューのような要素の表示に大きな影響を与える可能性があります。


## 3. 具体例
このセクションでは、`overflow` プロパティがドロップダウンメニューの表示にどのように影響を及ぼすかを示すシンプルなHTMLとCSSのコード例を提供します。

HTMLコード
```html
Copy code
<div class="dropdown-container">
    <button class="dropdown-button">メニュー</button>
    <div class="dropdown-content">
        <a href="#">リンク 1</a>
        <a href="#">リンク 2</a>
        <a href="#">リンク 3</a>
    </div>
</div>
```

CSSコード
```css
Copy code
.dropdown-container {
    width: 200px;
    overflow: hidden; /* これが問題を引き起こす */
    position: relative;
}

.dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

.dropdown-container:hover .dropdown-content {
    display: block;
}
```
このコードでは、`.dropdown-container` に `overflow: hidden;` を設定しています。これにより、ドロップダウンメニューの一部が `.dropdown-container` の境界を超えた際に見切れる問題が発生します。 `overflow: auto` でも、スクロールをしないとドロップダウンが表示されないということになります。


## 4. 問題点についての解説

### `overflow` プロパティによる問題の発生

`overflow` プロパティ（`hidden` や `auto` の値）がドロップダウンメニューの表示にどのように問題を引き起こすかを理解するためには、CSSのレンダリングメカニズムを考慮する必要があります。

1. **コンテナの境界によるクリッピング**: `overflow` プロパティが `hidden` や `auto` に設定されている場合、その要素のコンテンツがコンテナの境界を超えたとき、超えた部分は表示されません。これは、コンテンツがコンテナ内に収まるように制限されるためです。

2. **スクロールバーの影響**: `overflow: auto` の場合、コンテンツがコンテナの境界を超えるとスクロールバーが表示されます。しかし、ドロップダウンメニューのようにコンテナの外側に表示されるべきコンテンツにとっては、このスクロールバーは不要かつ不適切な挙動を引き起こします。

### 絶対配置された要素の挙動

ドロップダウンメニューは通常、`position: absolute` または `position: fixed` を使用してページ上の特定の位置に配置されます。これらのプロパティは要素を通常のドキュメントフローから取り除き、指定した位置に配置しますが、以下の問題があります：

1. **スクロールとの非同期**: 絶対配置された要素は、親要素がスクロールしてもその位置が変わらないため、スクロールに追従しません。これは、ドロップダウンメニューが親要素のビューポート内で動的に位置を変える必要がある場合に問題となります。

2. **スタッキングコンテキストの影響**: `position: absolute` または `position: fixed` は新しいスタッキングコンテキストを作成し、これが `z-index` の挙動に影響を及ぼします。親要素に `overflow` プロパティが設定されている場合、スタッキングコンテキストはドロップダウンの表示に影響を与え、意図しないクリッピングが発生することがあります。

### ブロック整形コンテキスト（BFC）との関係

ドロップダウンメニューのような絶対配置された要素は、ブロック整形コンテキスト（BFC）の影響を受けます。BFCは、親要素の `overflow` などのプロパティによって形成され、その内部でのレイアウトは外部の要素に影響されません。したがって、`overflow` プロパティが `hidden` や `auto` に設定されている要素は新しいBFCを形成し、その内部でドロップダウンメニューがクリップされる原因となり得ます。このため、ドロップダウンメニューの表示問題を解決するには、BFCの挙動を理解し、適切に扱う必要があります。
## 5. 終わりに

この記事を通して、`overflow` プロパティと絶対配置された要素（特にドロップダウンメニュー）の間の複雑な相互作用について理解を深めました。まとめます：

1. **親要素の `overflow` プロパティ**: これが `hidden` や `auto` に設定されている場合、ドロップダウンメニューが見切れる原因となる可能性があります。

2. **絶対配置された要素の挙動**: 絶対配置された要素（`position: absolute` または `position: fixed`）は親要素のスクロール動作と連動しません。

3. **BFCの理解と適用**: ドロップダウンメニューが意図通りに表示されるようにするには、ブロック整形コンテキスト（BFC）の挙動を理解し、適切に扱う必要があります。

この問題が発生する主な時は、ドロップダウンメニューを含むコンポーネントが `overflow` によってクリッピングされる状況です。この問題を回避するためには、`overflow` プロパティを持つ親要素からドロップダウンメニューを外に移動するか、JavaScriptを使用してドロップダウンメニューの位置を動的に管理するなどの方法が考えられます。

このようなCSSの挙動を理解することは、効果的でユーザーフレンドリーなウェブインターフェースを作成する上で重要です。