CSSレイアウトの基本のき。absolute, fixed, sticky, relativeについて。

#absolute, fixed, sticky, relativeの奥深さ
それぞれ概ね以下のように理解している人は多いと思います
- fixed: 画面を基準とした配置
- absolute: 親要素を?基準とした絶対位置
- relative: 親要素からの相対位置(???)
- sticky: 画面にひっついてくる

しかし、このように理解していても、`postion: aboslute`や、`position: fixed`を行うとすぐにレイアウトが崩れてしまい訳が分からなくなるという人は多いのではないでしょうか。

なぜそのような事が起きるかというと、`absolute`.`sitcky`,`fixed`,`relative`などを設定した要素に適用される**Positioned要素**という概念と、Positioned要素の基準位置となる**Containing Block**、そしてPositioned要素の**親要素のサイズ計算への影響**について正しく理解していないためです。

少し難しいですが、Positioned 要素とContaining Block,そしてPositioned要素のサイズ計算について確認していきましょう。

##Positioned Element(要素)
Positioned要素とは、HTMLの通常の配置フローから外れる要素です。
`absolute`などを利用するとPositioned要素となり、他の配置フローとは異なった考え方をする必要が出てきます。
どのような場合にPositioned ELementとなるのかは正確に把握しましょう。

##Positioned要素に該当する要素
positionプロパティーが以下の値の時、要素はPositioned要素となります。
- `fixed`
- `absolute`
- `relative`
- `sticky`
Positioned要素でないのはデフォルトの`static`だけです。
それ以外の場合は通常の配置フローと異なった考え方をする必要があります。

##Containing Block
Positioned要素の配置フローの基準位置となる場所(仮想の箱)が「Containing Block」です。
それぞれのPositioned要素ごとに、どこがContaining Blockとなるかは異なります。
Containing Blockを正しく把握しない事が混乱の元なので、正確に把握する必要があるでしょう。

##それぞれのContaining Block
それぞれのpositionプロパティーに対応するContaining Blockがどれかは以下の通りです。

###relative, staticの場合
この二つは通常通りの場所が基準となります。直近の親要素の上部(手前に兄弟要素がある場合、その要素を除いた部分)がContaining Blockとなります。

relativeがstaticと違うのは以下の2点です。
- 1.topやleftなどの値を設定できる。基準位置はContaining Block
- 2.子要素のPositioned要素のContaining Blockとして基準位置となる

2の特徴は特に重要で、relative要素は自身の配置をずらす目的よりも、`absolute`の子要素の位置を調整するために使う事の方が多いように思います。

###stickyの場合
stickyは非常に紛らわしいのですが、こちらも`relative`,`static`と同様、直近の親要素がContaining Blockとなり、通常の配置フローにしたがって配置されます。

しかし、topなどの基準位置は、**直近の親要素のうち,`overflow`が「`hidden`,`auto`もしくは`scroll`」となっているもの**となり、**親要素のoverflowが`visible`(default)となっているとstickyは機能しなく**なります。** overlowが設定されている要素が存在しない場合はviewportが基準**となります。

かなり複雑ですが、relativeとfixedの両方の要素+アルファの性質があるといった感じです。

例えば以下の場合、`id=3`の`div`は`id=1`の上から`50px`の距離を取るように配置されます。
`id=1`の上枠から50pxに引っかかるように挙動し、**`id=2`(container block。Container Blockと固定の基準位置は異なる)**の下枠にぶつかるまで画面にくっついてきます。

```html:example.html
<div id="1" style="position: overflow: hidden;">
  <div id="2">
    <div  id="3" style="position: fixed; top: 50px;"></div>
  </div>
</div>
```

**画面の枠が基準となると理解している人も多いように思いますが、違うパターンになることも非常に多いです。**



###absoluteの場合
`absolute`の場合、直近の親のPositioned要素がContaining Blockです。
例えば以下の場合、`id=3`の`div`の基準となるのは、2個上の親である `id=1`の`div`です。
`id=1`のdivの上の枠から50pxの位置に配置されます。

`id=1`のpositionが`relative`や`absolute`, `fixed`でも同様の結果となります。

```html:example.html
<div id="1" style="position: fixed">
  <div id="2">
    <div  id="3" style="position: absolute; top: 50px;"></div>
  </div>
</div>

```

###fixedの場合
Viewport(ブラウザの枠)が基準となります。
下の場合、id=1やid=2の要素は無視され、ブラウザの上の枠から50pxの位置に配置されます。

```html:example.html
<div id="1" style="position: relative">
  <div id="2">
    <div  id="3" style="position: fixed; top: 50px;"></div>
  </div>
</div>

```

##Positioned要素の親要素のサイズの計算
HTMLにおいて、親要素のwidth, heightは指定しなければ内側の要素のサイズを計算してボトムアップ式に決定されます。しかし、子要素がabsolute, もしくはfixedの場合は親要素のサイズに影響を与えません。


##まとめ
以上をまとめると以下のようになります。

| position         | Positioned |  Container Block | 親要素のサイズ計算に含むか |
|:-----------------|-----------:|:------------------:|:--------------------:|
| static           |×           |  親要素             |含む                   |
| relative         |○           |  親要素             |含む                   |
| sticky           |○           |  親要素: 固定の基準位置はviewport(もしくは直近のoverflowが設定された親要素)|含む|
| fixed            |○           |         viewport         |含まない|
| absolute         |○           |     親のPositioned要素         |含まない|


CSSがうまく機能しない理由の大半はこのへんの理解が深まれば解消するのではないかと思います。

しかし、ここまででも十分複雑ですがここにも記述しきれなかった例外規則なども多数あります。
困った時はちゃんとドキュメントに当たるようにしましょう。


###参考
https://developer.mozilla.org/en-US/docs/Web/CSS/position