なぜ親要素に position: relative, 子要素に position: absolute を指定すると 子要素の位置をいい感じに指定できるのか

ある要素を他の要素に重ねて表示したかったり
特定の位置から〇〇px動かした、この位置に要素を配置したい！といった際に
以下のように、親の要素に`position: relative`, 子の要素に`position: absolute`を指定することで
子要素の位置を自由に配置することが一般的かと思います。

<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="qBwbjPO" data-preview="true" data-user="Keito13" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Keito13/pen/qBwbjPO">
  position-sample1</a> by KeitoSato (<a href="https://codepen.io/Keito13">@Keito13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

**なぜ親要素に`position: relative`, 子要素に`position: absolute`を指定すると子要素の位置をいい感じに指定できるのか**

この記事では、なんとなく「こういうものなんだ」としか理解できていない方と一緒に、CSSのpositionプロパティについて確認していこうと思います。

## positionプロパティの値
positionプロパティで主に使用される値は以下の通りです。[^1]
- static
- relative
- absolute
- fixed
- sticky

それでは、positionの基本である`static`と
主題である`relative`と`absolute`について、その使い方を詳しく見ていきましょう。

## position: static
`static`はpositionプロパティの規定値です。
positionプロパティを特に何も指定しなかった場合と、同じ振る舞いになります。

要素の配置位置は指定できず、画面の左上から順番に配置されていきます。
つまり、 `top`や`right`といった位置指定のプロパティや
`z-index`による要素の重なり順の指定は
**`position: static`が指定された要素には行えません！**
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="XWQdVYK" data-preview="true" data-user="Keito13" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Keito13/pen/XWQdVYK">
  static-sample</a> by KeitoSato (<a href="https://codepen.io/Keito13">@Keito13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## position: relative
`relative`とは「相対的」という意味です。
「相対的」をオンライン辞書の[weblio](https://www.weblio.jp/)で引いてみると
[デジタル大辞泉](https://www.weblio.jp/content/%E7%9B%B8%E5%AF%BE%E7%9A%84?dictCode=SGKDJ)で以下の通り解説されております。
>他との関係において成り立つさま。また、他との比較の上に成り立つさま。「—な価値」「物事を—に見る」⇔絶対的。

positionプロパティにおける`relative`は、まさに相対的な位置の指定方法です。
では、何と関係して位置を決めているかというと、**元々自分が表示されるはずだった位置**です。

`position: relative`が指定された要素は、まず`position: static`の時と同様に、画面左上から順番に配置されます。
その後、**自分自身が表示されている位置を基準に、`top`や`right`などで指定された分だけ自身を移動させます。**
この時、**後続の要素の表示位置には影響を与えません！**
つまり、自分自身が元々表示されていた領域を詰めることはしないということです。
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="WNWwyPo" data-preview="true" data-user="Keito13" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Keito13/pen/WNWwyPo">
  relative-sample</a> by KeitoSato (<a href="https://codepen.io/Keito13">@Keito13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## position: absolute
`absolute`は、「絶対的」という意味です。
こちらも[weblio](https://www.weblio.jp/)で引いてみると
[デジタル大辞泉](https://www.weblio.jp/content/%E7%B5%B6%E5%AF%BE%E7%9A%84)で以下の通り解説されています。
>他の何物ともくらべようもない状態・存在であるさま。「—な信頼を得る」「—に有利な立場」⇔相対的。

positionプロパティにおける`absolute`は、指定された要素の元々表示されていた位置なんて気にしません。
こいつの位置はここだ！と指定した箇所に表示させます。
では、一体どこを基準にして配置を決めるのかというと…
**要素の祖先を辿っていって、最初に位置が指定されている要素が基準となります。**

「位置が指定されている」とはどういうことかというと
positionの指定が `relative`, `absolute`, `fixed`, `sticky` のいずれかである
ということです。

この仕様に、この記事の表題である
「**親要素に`position: relative`, 子要素に`position: absolute`を指定すると子要素の位置をいい感じに指定できるのは何故か**」の答えが詰まっています！

### position: absoluteの要素の親は、relativeじゃなくても良い
`position: absolute`の要素の位置を決めるのは、祖先の要素で最初に位置が指定されている要素です。
なので、なにも親要素のpositionが`relative`でなくても、`absolute`の位置指定は可能ということになります。
<p class="codepen" data-height="300" data-default-tab="css,result" data-slug-hash="JjVKBaQ" data-preview="true" data-user="Keito13" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/Keito13/pen/JjVKBaQ">
  Untitled</a> by KeitoSato (<a href="https://codepen.io/Keito13">@Keito13</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

上のCodePenでは、`relative`, `absolute`, `fixed`, `sticky`による位置指定がされている親要素をそれぞれ持つ、`position: absolute`の要素を見ることができます。
親要素のpositionが`relative`でなくとも、配置の指定が問題なく行われていることがわかるかと思います。

### relativeとabsoluteがセットで使われやすい理由
`position: absolute`の要素の親は、`relative`じゃなくても良いことはわかりました。
では、なぜ`relative`と`absolute`は
まるでイディオムのように、セットで使われることが多いのでしょうか。

それは、`position: relative`以外の要素は、ちょっとクセがあるからだと、言えるかもしれません。

#### absolute
`absolute`は上で述べた通り、元々表示されていた位置なんて気にしない、"絶対的"な存在にしてしまいます。
`relative`は、自分自身が元々表示されていた領域を確保したまま、配置を移動しますが
`absolute`は、**自分自身の元々の表示領域を確保しません。**
後続の要素は詰めて配置されるという仕様になっています。

#### fixed
`fixed`も、自分自身の表示領域を確保しません。
`fixed`を持つ要素は、スクロールの影響を受けず
常にページの指定された位置に表示され続けます。
子要素に`absolute`の要素があれば、その要素も一緒に
常にページの指定された位置に、表示され続けることになります。

#### sticky
`sticky`は、`relative`と同様に、自身の表示領域を確保します。
しかし、画面がスクロールされ指定された位置に自身が表示されると
`fixed`のように、その場所に留まり続けて表示されるという、一風変わった挙動となります。
子要素に`absolute`の要素があればその要素も一緒に、その場に留まり表示され続けます。

#### かたや、relative
`relative`は上述した通り、自身の元々の表示領域を確保します。
更に言えば、`top`や`right`など配置を移動させる指定を行わなければ
`static`の要素と何ら変わらず、元々の自分の位置にいてくれます。
こうすれば、位置を指定する要素は、`absolute`の子要素だけで良くなり
他要素の表示位置に影響も与えません。
また、最終的にどこに表示されるのかも、他の値に比べてとても分かりやすいです。

**これが、relativeとabsoluteがセットで使われやすい理由だと言えるでしょう！**

## 本記事のまとめ
- `position: absolute`の特徴
    - 祖先の要素を近い順に辿って、`relative`, `absolute`, `fixed`, `sticky`のいずれかが最初に指定された要素の位置を基準に、自身の位置を移動する
    - 自分自身が元々表示されるはずだった領域の確保は行われず、後続の要素が詰めて表示される
- `position: relative`の特徴
    - 自分自身のデフォルトの表示位置を基準に、位置を移動できる
    - 自分自身が元々表示されるはずだった領域は確保され、後続の要素の表示位置に影響を与えない
    - 位置を移動させなければ、`position: static`の要素と見た目は変わらずに配置される

:::note info
これらの特徴から…

`position: absolute`の要素以外は、特にいじらずに配置させたい！
そんな時に、親要素のpositionを`relative`
目的の要素を子要素にして、positionに`absolute`を指定すると
目的の要素以外に影響を与えずに、自由な要素の配置ができるぞ！
:::

## 参考URL
- [MDN Web Docs - position](https://developer.mozilla.org/ja/docs/Web/CSS/position)
[^1]: これらの他、`initial`や`unset`といった、複数のプロパティで指定することができる値もあります