JavaScript(でもほぼCSS) 第7回 positionの動作

# はじめに
今回はCSSのpositionについて整理したいと思います。
というのも、モーダルウィンドウを作りたいと思ったからです。
モーダルウィンドウはよく画面の真ん中に表示されると思いますが、そのための動作のひとつとして、positionの動きを整理しておいたほうが良いと思いました。
色々インターネット上に情報はありますし、MDN Web docにもソースはありますが、自分で納得を得たくまとめたいと思います。

# 今回実施する内容
Div要素をpositionを使用してどのような位置にくるかをまとめていきたいと思います。

# ソースコード(Git Hub)
https://github.com/Build-Mount/JS_07_position

# 環境
OS: Windows 10 JP (64bit)
Microsoft Edge: バージョン 120.0.2210.61 (公式ビルド) (64 ビット)

# 参考
[position](https://developer.mozilla.org/ja/docs/Web/CSS/position)
https://developer.mozilla.org/ja/docs/Web/CSS/right
[top](https://developer.mozilla.org/ja/docs/Web/CSS/top)
[right](https://developer.mozilla.org/ja/docs/Web/CSS/left)
[bottom](https://developer.mozilla.org/ja/docs/Web/CSS/bottom)
[right](https://developer.mozilla.org/ja/docs/Web/CSS/right)

# 用語

# 結論
先に結論を表にまとめす。

|position|位置基準|top, left,bottom, right|width, height調整|後続の要素影響|スクロール|
|:--|:--|:--|:--|:--|:--|
|static|通常のフロー|効果なし|なし|なし|する|
|relative|通常のフロー|top, leftかbottom, rightの一方だけ使用|なし|なし|する|
|absolute|直近の祖先（親）|top, left, bottom, right使用可|あり|あり|する|
|fixed|画面|top, left, bottom, right使用可|あり|あり|する|
|sticky|通常のフロー|top, left, bottom, right使用可|なし|なし|粘着|

:::note info
位置基準は、`top`や`left`などの位置指定プロパティの基準となる要素を示す。
:::
:::note info
width, height調整は、`top`、`bottom`設定時にその間の高さが埋まるかどうか、および`left`、`right`設定時にその間の幅が埋まるかどうかを示す。
:::
:::note info
後続の要素影響は、`position`設定によってその後に記載される要素の位置に影響があるかを示す。
:::

## `top`、`left`設定時の動作
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/a6709be3-be8e-e1a2-de47-d9bf493c0957.png)


## `bottom`、`right`設定時の動作
- `relative`は以下の通り。その他も考え方は同じため省略。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/e153d8cf-870f-b91a-817b-55e7fee29f8f.png)

## `top`、`left`、`bottom`、`right`設定時の動作
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/ca70f46d-424d-c771-4948-b923f62c87eb.png)

# potisionの動作の調査
1つのdivに対して、[position](https://developer.mozilla.org/ja/docs/Web/CSS/position)に記載のあるpositionのプロパティ値を、記載の内容を鑑みて変更して、それがどのような結果になるかを整理したいと思います。

## 基本画面
posotionを設定しない場合の画面は以下の通りです。これをもとに`position`や関連するプロパティを設定し、動作を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/b32dc84c-4476-0047-93d1-f64c94965539.png)

## コンソール出力
基本画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:auto
right:auto
bottom:auto
left:auto
height:24px
zIndex:auto
width:808px
fontSize:16px
```

## 元となるソースコード
```html:position.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Position</title>
    <link rel="stylesheet" href="position.css" type="text/css">
    <script src="position.js" defer></script>
</head>
<body>
    <div id="parentDiv">
        <div>fiirstDiv</div>
        <div id="targetDiv">
            あいうえおかきくけこ
        </div>
        <div class="clsDiv">あいうえおかきくけこ</div>
    </div>
</body>
</html>
```
```css:position.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
}
```
```javascript:position.js
console.log(`top:${getComputedStyle(document.getElementById("targetDiv")).top}`);
console.log(`right:${getComputedStyle(document.getElementById("targetDiv")).right}`);
console.log(`bottom:${getComputedStyle(document.getElementById("targetDiv")).bottom}`);
console.log(`left:${getComputedStyle(document.getElementById("targetDiv")).left}`);
console.log(`height:${getComputedStyle(document.getElementById("targetDiv")).height}`);
console.log(`zIndex:${getComputedStyle(document.getElementById("targetDiv")).zIndex}`);
console.log(`width:${getComputedStyle(document.getElementById("targetDiv")).width}`);
console.log(`fontSize:${getComputedStyle(document.getElementById("targetDiv")).fontSize}`);
```
`position.html`では、`<body>`の下に親となる`<div id="parentDiv">`を準備し、その配下に`div`タグを３つ作成します。
`position.css`では、`#parentDiv`で親となる`div`タグの範囲を背景色黄色で示します。
１つ目の子である`div`タグはスタイルは設定しません。
２つ目の子である`div`タグは、`position`や`top`, `bottom`, `left`, `right`プロパティの値を設定しますが、最初は何も設定せず、これ以降でそれぞれ試します。
３つ目の子である`div`タグは、２つ目の子の`div`タグの動作によって表示位置が影響を受けることがあるため、それがわかるように背景色を緑色で示します。
なお、`div`タグはBlock要素であり、何も設定しないと幅は画面の幅に合わせて設定されます。
`position.js`では、2つ目の子である"targetDiv"の`top`、`right`、`bottom`、`left`、`zIndex`、`height`、`width`、`fontSize`の値をコンソールに表示します。

## position:static(規定値)の動作
[position](https://developer.mozilla.org/ja/docs/Web/CSS/position)の記載を抜粋しつつ、動作を確認します。
>`static`
>要素は文書の通常のフローに従って配置されます。 `top`, `right`, `bottom`, `left`, `z-index` プロパティは効果がありません。これが既定値です。

### `static`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/3df2ead0-91f6-24e5-46b4-c7aae81e8df6.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:auto
right:auto
bottom:auto
left:auto
height:24px
zIndex:auto
width:808px
fontSize:16px
```

### ソースと説明
`position.html`はファイル名を変更して`positionStatic.html`にし参照するCSSファイル名やJavaScriptファイル名を変更していますが、それ以外の変更がないため、説明を割愛します。GitHubにはソースとしては載せておきます。
```css:positionStatic.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: static;
}
```

`position: static`は規定値であり、`static`を設定しても、設定していない時と動作は変わりませんでした。
**要素は文書の通常のフローに従って配置されます。** と記載のある通り、１つ目の子の`div`タグの次に２つ目の今回`position`の値を変えていくターゲットの`div`タグが表示され、その後に、３つ目の子の`div`タグが配置されました。

## position:staticとtop, leftの動作
### `static`、`top`、`left`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/f20d8c7b-b4ff-e654-f54a-cf9999b8a947.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:32px
right:auto
bottom:auto
left:32px
height:24px
zIndex:auto
width:808px
fontSize:16px
```

### ソースと説明
htmlファイル、JavaScriptファイルは上記記載通り、割愛します。
```css:positionStatic2.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: static;
  top: 2em;
  left: 2em;
}
```

**`top`, `right`, `bottom`, `left`, `z-index` プロパティは効果がありません。** と記載のある通り、`top`、`left`を設定しても画面上は変わりませんでした。
しかし、コンソール出力では、`top: 32px`となり、設定としてはされていることを確認しました。

## position:relativeの動作
>`relative`
>要素は文書の通常のフローに従って配置され、 `top`, `right`, `bottom`, `left` の値に基づいて自分自身からの相対オフセットで配置されます。オフセットは他の要素の配置には影響を与えません。つまり、ページレイアウト内で要素に与えられる空間は、位置が `static` であった時と同じです。
>
>`z-index` の値が `auto` でない場合、新しい重ね合わせコンテキストを生成します。 `table-*-group`, `table-row`, `table-column`, `table-cell`, `table-caption` の要素における効果は未定義です。

### `relative`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/52ff1468-0c16-29cd-d382-6c0f0a523f5d.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:0px
right:0px
bottom:0px
left:0px
height:24px
zIndex:auto
width:808px
fontSize:16px
```

### ソースと説明
htmlファイル、JavaScriptファイルは上記記載通り、割愛します。
```css:positionRelative.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: relative;
}
```
`position: relative`に設定すると、画面上では`static`と同様ですが、コンソール出力では、`top: 0px`、`right: 0px`、`bottom: 0px`、`left: 0px`となっていることを確認しました。

## position:relativeとtop、leftの動作
### `relative`、`top`、`left`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/28ef96b5-9bf8-235a-a801-601142943cb7.png)
赤字は右にはみ出しました。
Edgeでは横スクロールバーが表示され、右にスクロールすることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/35a2c691-9c30-4209-5fb4-97787b920e3e.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:32px
right:-32px
bottom:-32px
left:32px
height:24px
zIndex:auto
width:808px
fontSize:16px
```

### ソースと説明
htmlファイル、JavaScriptファイルは上記記載通り、割愛します。
```css:positionRelative2.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: relative;
  top: 2em;
  left: 2em;
}
```

`position:relatiive`に設定時は、**要素は文書の通常のフローに従って配置され、 `top`, `right`, `bottom`, `left` の値に基づいて自分自身からの相対オフセットで配置されます。** と記載のある通り、２つ目の子の`div`タグは、元の場所から`top`、`left`が2em分移動、`fontSize`が16pxのため掛ける2倍で32px分移動しました。
**オフセットは他の要素の配置には影響を与えません。** と記載のある通り、元の場所は空白として残り、３つ目の子の`div`タグ（背景色緑色の部分）は移動しませんでした。
驚いたのは、コンソール出力の結果で、`right:-32px`、`bottom:-32px`で、設定していないのに値が入っていたことでした。
確かに`right`は画面右部からのオフセットであり、`bottom`は含有ブロック下部からのオフセットなため、-32pxと言われればそうなのだと思いました。

## position:relativeとtop、left、bottom、rightの動作
### `relative`、`top`、`left`、`bottom`、`right`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/28ef96b5-9bf8-235a-a801-601142943cb7.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:32px
right:32px
bottom:32px
left:32px
height:24px
zIndex:auto
width:808px
fontSize:16px
margin:0px
padding:0px
border:0px
```

### ソースと説明
htmlファイル、JavaScriptファイルは上記記載通り、割愛します。
```css:positionRelative3.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: relative;
  top: 2em;
  left: 2em;
  bottom: 2em;
  right: 2em;
}
```
[top](https://developer.mozilla.org/ja/docs/Web/CSS/top)には、以下の記載があります。
>`top` と `bottom` の両方が指定されており、 `position` が `absolute` または `fixed` に設定されており、かつ `height` が未指定 (`auto` または `100%` のどちらか) の場合は、 `top` と `bottom` の距離が尊重されます。それ以外の場合、 `height` が何らかの形で制約されていた場合、または `position` が `relative` に設定されていた場合は、 `top` プロパティが優先されて `bottom` プロパティは無視されます。

上記の通り今回は両方設定したため、コンソール出力では、`bottom: 32px`に設定されているように見えますが、画面では`bottom`設定は無視されました。

[left](https://developer.mozilla.org/ja/docs/Web/CSS/left)には、以下の記載があります。
>`left` と `right` の両方が定義されていて、幅の制約がない場合、要素は両方を満たすように伸縮されます。要素が両方を満たすように伸縮できない場合、要素の位置は過剰指定になります。このような場合、包含ブロックが左書きの場合は `left` の値が優先され、包含ブロックが右書きの場合は `right` の値が優先されます。

上記の通り今回は両方設定したため、コンソール出力では、`right:32px`に設定されているように見えますが、画面では`right`設定は無視されました。
`左書き`は、`direction`の値のことでがデフォルトでは左書きであるため、`left`が優先されるということだと思います。

結局、`relative`の場合、`bottom`、`right`は、`top`、`left`と同時に使用し`div`タグの幅や高さを調整するようなことはできず、どちらかだけを使用するということだと思います。

## position:absoluteの動作
>`absolute`
>要素は文書の通常のフローから除外され、ページレイアウト内に要素のための空間が作成されません。直近の配置されている祖先があれば、それに対して相対配置されます。そうでなければ、初期の包含ブロックに対して相対配置されます。最終的な位置は `top`, `right`, `bottom`, `left` の値によって決定されます。
>
>この値では、 z-index の値が auto ではない場合、新しい重ね合わせコンテキストを作成します。絶対位置指定ボックスのマージンは、他の要素のマージンと相殺されません。

### `absolute`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/127b237d-8663-f493-4ad9-3f5f40fce3ba.png)

補足
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/0084d11a-5d3b-fbbf-dcea-527feb3a634a.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:32px
right:656px
bottom:602px
left:8px
height:24px
zIndex:auto
width:160px
fontSize:16px
margin:0px
padding:0px
borderWidth:0px
```

### ソースと説明
htmlファイルは上記記載通り、割愛します。
```css:positionAbsolute.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: absolute;
}
```
```javascript:positionAbsolute.js
console.log(`top:${getComputedStyle(document.getElementById("targetDiv")).top}`);
console.log(`right:${getComputedStyle(document.getElementById("targetDiv")).right}`);
console.log(`bottom:${getComputedStyle(document.getElementById("targetDiv")).bottom}`);
console.log(`left:${getComputedStyle(document.getElementById("targetDiv")).left}`);
console.log(`height:${getComputedStyle(document.getElementById("targetDiv")).height}`);
console.log(`zIndex:${getComputedStyle(document.getElementById("targetDiv")).zIndex}`);
console.log(`width:${getComputedStyle(document.getElementById("targetDiv")).width}`);
console.log(`fontSize:${getComputedStyle(document.getElementById("targetDiv")).fontSize}`);
console.log(`margin:${getComputedStyle(document.getElementById("parentDiv")).margin}`);
console.log(`padding:${getComputedStyle(document.getElementById("parentDiv")).padding}`);
console.log(`borderWidth:${getComputedStyle(document.getElementById("parentDiv")).borderWidth}`);
```
`position: absolute`に設定すると、**要素は文書の通常のフローから除外され、ページレイアウト内に要素のための空間が作成されません。** と記載のあるように、通常のフローから外れたため３つ目の子の`div`タグは２つ目の子の`div`タグがなかったかように１つ目の子の`div`タグの直後に配置されました。
２つ目の子の`div`タグは`position: static`の時と同様の位置には配置されました。`top`、`left`などを設定しないと、もともとの場所に配置されると理解しました。
`width`については、文字が入る分だけの幅に変わっており、[position](https://developer.mozilla.org/ja/docs/Web/CSS/position)には、
>ほとんどの場合、絶対位置指定要素に `height` および `width` が `auto` が設定されると、内容に合うように大きさが調整されます。しかし、非置換要素で絶対位置指定要素は、 `top` および `bottom` を指定して `height` を指定しない (つまり `auto` の) ままにすることで、利用できる垂直の空間を埋めることができます。同様に、 `left` および `right` を指定して `width` を `auto` のままにすることで、利用できる水平の空間を埋めることができます。

と記載があります。「絶対指定位置要素」は`position: absolute`、もしくは、`fixed`に設定した要素であり、`width`は未指定の初期値は`auto`であり、今回はこのケースに合致することから、**内容に合うように大きさが調整** されたと理解しました。
`height`については、もともとブロック要素で１行だっため変化は見られませんが、同様の動作になると理解しました。

コンソール出力した`top`、`left`などのプロパティの値は0pxになると思っていましたが、実際には、`top: 32px`、`right: 656px`、`bottom: 641px`、`left: 8px`となり、位置が指定されていました。
これは、**直近の配置されている祖先があれば、それに対して相対配置されます。そうでなければ、初期の包含ブロックに対して相対配置されます。** とあるため、親の`div`タグからの相対位置が設定されました。
`top`は32pxで、一行の高さ分の24pxではなく、8px分余分で、`left`も8pxで0pxではなく、少しオフセットがあると理解しました。気になったため、JavaScriptファイルを少し修正して、`margin`、`padding`、`border`のサイズを確認してみましたが、いずれも0pxで、8pxのオフセットの理由はわかりませんでしたが、レイアウトの都合上の話なのかもしれません。

## position:absoluteとtop、leftの動作
### `absolute`、`top`、`left`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/ec6fb7bd-6189-6b93-4fdd-501c14eee81e.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:56px
right:624px
bottom:578px
left:40px
height:24px
zIndex:auto
width:160px
fontSize:16px
margin:0px
padding:0px
borderWidth:0px
```

### ソースと説明
htmlファイルは上記記載通り、割愛します。
Javascriptファイルは`positionAbsolute.js`と同様のため、割愛します。
```css:positionAbsolute2.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: absolute;
  top: 56px;    /* 8 + 24 + 24 = 56 */
  left: 40px;   /* 8 + 16 + 16 */
}
```
`position: absolute`に設定時に`top`、`left`を設定すると、親の`div`タグからの相対オフセットで配置されました。
`top: 56px`は、8pxのオフセットに加え、2行分(24px + 24px)でちょうど2行の下に配置するように計算した値です。
`left: 40px`は、8pxのオフセットに加え、2文字分右に配置するように計算した値です。
`top`も`left`も期待通り動作しました。

## position:absoluteとtop、left、bottom、rightの動作
### `absolute`、`top`、`left`、`bottom`、`right`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/7dbaa650-6cc4-cd97-5a50-0a623cc26af6.png)
補足
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/529811f5-d921-b403-29bb-0d648b9fd680.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:56px
right:32px
bottom:32px
left:40px
height:570px
zIndex:auto
width:752px
fontSize:16px
margin:0px
padding:0px
borderWidth:0px
```

### ソースと説明
htmlファイルは上記記載通り、割愛します。
Javascriptファイルは`positionAbsolute.js`と同様のため、割愛します。
```css:positionAbsolute2.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: absolute;
  top: 56px;    /* 8 + 24 + 24 = 56 */
  left: 40px;   /* 8 + 16 + 16 */
  bottom: 2em;
  right: 2em;
}
```
`position: absolute`に設定時に`top`、`left`、`bottom`、`right`を設定すると2つ目の子の`div`タグは、親の`div`タグからの相対オフセットで配置されました。
高さは、`top`、`bottom`の間の垂直を埋める高さになり、横幅は、`left`、`right`の間の幅を埋める幅になりました。

## position:fixedの動作
>`fixed`
>要素は文書の通常のフローから除外され、ページレイアウト内に要素のための空間が作成されません。ビューポートによって定められた初期の包含ブロックに対して相対配置されますが、祖先の一つに `transform`, `perspective`, `filter` の何れかのプロパティが `none` 以外 (CSS Transforms 仕様書を参照) に設定されている場合は例外で、その場合は祖先が包含ブロックとしてふるまいます。 (なお、包含ブロック形成に寄与している `perspective` と `filter` に矛盾のあるブラウザーがあります。) 最終的な位置は `top`, `right`, `bottom`, `left` の値によって決定されます。
>
>この値は、常に新しい重ね合わせコンテキストを作成します。印刷文書の場合、要素は各ページの同じ位置に配置されます。

### `fixed`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/8a00ee1e-a457-b7ba-0fb2-4840e8e143bd.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:32px
right:656px
bottom:602px
left:8px
height:24px
zIndex:auto
width:160px
fontSize:16px
```

### ソースと説明
htmlファイル、JavaScriptファイルは上記記載通り、割愛します。
```css:positionfixed.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: fixed;
}
```
`position: fixed`に設定すると、画面上では`absolute`と同様ですが、**ビューポートによって定められた初期の包含ブロックに対して相対配置されます** と記載のある通り、ビューポートから相対配置されます。要するに画面の端から相対配置されます。これに対して`absolute`は祖先から相対配置されます。
これがわかる例を次の章で記載します。

## position:fixedとtop、leftの動作
### `fixed`、`top`、`left`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/7c6f5214-fb0c-8779-c320-fa0dc7debe2a.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:0px
right:664px
bottom:634px
left:0px
height:24px
zIndex:auto
width:160px
fontSize:16px
```

### ソースと説明
htmlファイル、JavaScriptファイルは上記記載通り、割愛します。
```css:positionFixed2.css
#parentDiv {
  background-color: yellow;
  position: absolute;
  top: 2em;
  left: 2em;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: fixed;
  top: 0px;
  left: 0px;
}
```
`position: fixed`に設定時の **ビューボードによって定められた初期の含有ブロックに対して相対配置されます**の確認のため、親の`div`タグを`position: absolute`、`top`、`left`を2emに設定し、２つ目の子の`div`タグに対しては、`top`、`left`を0emに設定し、２つ目の子の配置を確認できるようにしました。
結果としては、画面の通りで、２つ目の子の`div`タグは画面の左上に配置され、親の`div`タグは`top`、`left`ともに2emほど移動した場所に配置され、２つ目の子の`div`タグが親の`div`タグからの相対配置ではないことがわかりました。

## position:fixedとtop、left、bottom、rightの動作
### `fixed`、`top`、`left`、`bottom`、`right`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/5bc0be90-70ed-2420-977a-4ae5c3099f8e.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:32px
right:32px
bottom:32px
left:32px
height:594px
zIndex:auto
width:760px
fontSize:16px
```

### ソースと説明
htmlファイル、JavaScriptファイルは上記記載通り、割愛します。
```css:positionFixed3.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: fixed;
  top: 2em;
  left: 2em;
  bottom: 2em;
  right: 2em;
}
```
`position: fixed`に設定時に`top`、`left`、`bottom`、`right`を設定すると、ビューポートから相対オフセットで配置されました。
高さは、`top`、`bottom`の間の垂直を埋める高さになり、横幅は、`left`、`right`の間の幅を埋める幅になりました。動作は、`position: absolute`設定時と同じと理解しました。

## position:stickyの動作
>`sticky`
>要素は文書の通常のフローに従って配置され、直近のスクロールする祖先および包含ブロック (直近のブロックレベル祖先、表関連要素を含む) に対して `top`, `right`, `bottom`, `left` の値に基づいて相対配置されます。オフセットは他の要素の配置には影響を与えません。
>
>この値は、常に新しい重ね合わせコンテキストを生成します。なお粘着要素は、直近の祖先がスクロールしない場合でも、「スクロールの仕組み」を持つ直近の祖先 (`overflow` が `hidden`, `scroll`, `auto`, `overlay` として作成されたもの) に「粘着」します。これによって「粘着」のふるまいを効果的に抑止します (GitHub issue on W3C CSSWG を参照)。

### `sticky`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/b835bac7-eef9-198b-5801-0527c5e7995f.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:auto
right:auto
bottom:auto
left:auto
height:24px
zIndex:auto
width:809px
fontSize:16px
```

### ソースと説明
JavaScriptファイルは上記記載通り、割愛します。
```html:positionSticky.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Position</title>
    <link rel="stylesheet" href="positionSticky.css" type="text/css">
    <script src="positionSticky.js" defer></script>
</head>
<body>
    <div id="parentDiv">
        <div>fiirstDiv</div>
        <div id="targetDiv">
            あいうえおかきくけこ
        </div>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <div class="clsDiv">あいうえお</div>
    </div>
</body>
</html>
```
```css:positionSticky.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: sticky;
}
```
`positionSticky.html`については、`sticky`(粘着位置指定要素)のため、親の`div`タグに`<br>`で改行を多めに入れました。
**「粘着」とは、要するにブラウザ上でスクロールしたとしても、画面にへばりついてスクロールされないということです。** 細かくいうとスクロールされるポイントもありますので、それは後ほど記載します。
`sticky`設定時の画面では、スクロールバーのない全体の画面を載せております。
`position: sticky`に設定すると、**要素は文書の通常のフローに従って配置され、直近のスクロールする祖先および包含ブロック (直近のブロックレベル祖先、表関連要素を含む) に対して `top`, `right`, `bottom`, `left` の値に基づいて相対配置されます。** と記載のあるように、2つ目の子の`div`タグは`position: static`の時と同じ場所に配置されました。`top`、`left`などを設定しないと、もともとの場所に配置されると理解しました。

画面がスクロールするように、Edgeのサイズを小さくしても **「粘着」** 動作は見られません。
コンソール出力の`top`、`left`などの値は、`auto`になっており、** 直近のスクロールする祖先および包含ブロック (直近のブロックレベル祖先、表関連要素を含む) に対して `top`, `right`, `bottom`, `left` の値に基づいて相対配置されます。** と記載のあるように、具体的に設定しないと **「粘着」**は動作しないと理解しました。

## position:stickyとtop、leftの動作
### `sticky`、`top`、`left`設定時の画面
![sticky.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/186b5e91-d8fe-a39d-2875-89bf871e88a8.gif)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:80px
right:auto
bottom:auto
left:32px
height:24px
zIndex:auto
width:753px
fontSize:16px
```

### ソースと説明
JavaScriptファイルは上記記載通り、割愛します。
```html:positionSticky2.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Position</title>
    <link rel="stylesheet" href="positionSticky2.css" type="text/css">
    <script src="positionSticky2.css" defer></script>
</head>
<body>
    <div id="parentDiv">
        <div>fiirstDiv</div>
        <div id="targetDiv">
            あいうえおかきくけこ
        </div>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <div class="clsDiv">あいうえお</div>
    </div>
</body>
</html>
```
```css:positionSticky2.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: sticky;
  top: 5em;
  left: 2em;
}
```
`position: sticky`に設定時に`top`、`left`を設定すると、`top`については親の`div`タグからの相対位置で設定されましたが、`left`については効果がありませんでした。`width`は画面一杯となっており、これが要因で`left`は効果がなかったように見受けられます。
画面スクロールするようにすると、２つ目の子の`div`タグは位置固定されスクロールされませんでした。これが **「粘着」** の動作です。

## position:stickyとtop、leftの粘着の終わりの動作
### `sticky`、`top`、`left`の粘着の終わりの設定時の画面
![sticky2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/0322e677-655a-75a0-faf6-6685936d86ac.gif)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:32px
right:auto
bottom:auto
left:32px
height:24px
zIndex:auto
width:160px
fontSize:16px
```

### ソースと説明
JavaScriptファイルは上記記載通り、割愛します。
```html:positionSticky3.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Position</title>
    <link rel="stylesheet" href="positionSticky3.css" type="text/css">
    <script src="positionSticky3.js" defer></script>
</head>
<body>
    <div id="parentDiv">
        <div>fiirstDiv</div>
        <div id="targetDiv">
            あいうえおかきくけこ
        </div>
        <br>
        <br>
        <div class="clsDiv">あいうえお</div>
    </div>
    <div id="parentDiv2">
        <div>fiirstDiv</div>
        <div id="targetDiv2">
            さしすせそたちつてと
        </div>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <br>
        <div class="clsDiv">あいうえお</div>
    </div>
</body>
</html>
```
```css:positionSticky3.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: sticky;
  top: 5em;
  left: 2em;
}
```
`position: sticky`に設定時に`top`、`left`を設定すると **「粘着」** しますが、この **「粘着」** はずっと続くわけではありません。
[position](https://developer.mozilla.org/ja/docs/Web/CSS/position)には、以下の記載があります。
>粘着位置指定要素 (stickily positioned element) とは、 `position` の計算値が `sticky` である要素です。これは包含ブロックがフロールート (またはその中でスクロールするコンテナー) 内の指定されたしきい値 (例えば `top` に設定された `auto` 以外の値など) を達するまでは相対的な配置として扱われ、包含ブロックの反対の端が来るまでその位置に「粘着」するものとして扱われます。

上記の通り、**包含ブロックの反対の端が来るまでその位置に「粘着」する**ため、親の`div`タグを２つ作り、それぞれに`position: sticky`を設定し、1つ目の親の`div`タグの下端（反対側の端）が **「粘着」**の位置に到達すると、**「粘着」**した部分は一緒にスクロールしました。
２つ目の親の`div`タグ配下の２つ目の子の`div`タグも **粘着** することを確認しました。

## position:stickyとtop、left、bottom、rightの動作
### `sticky`、`top`、`left`、`bottom`、`right`設定時の画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405480/69b3b3f4-91f4-260f-f5dd-89185fb46017.png)

### コンソール出力
画面の赤字の「あいうえおかきくけこ」の各プロパティの値は以下の通りです。
```
top:32px
right:32px
bottom:32px
left:32px
height:24px
zIndex:auto
width:753px
fontSize:16px
```

### ソースと説明
htmlファイル、JavaScriptファイルは上記記載通り、割愛します。
```css:positionSticky4.css
#parentDiv {
  background-color: yellow;
}

.clsDiv {
  background-color: green;
}

#targetDiv {
  background-color: red;
  position: sticky;
  top: 2em;
  left: 2em;
  bottom: 2em;
  right: 2em;
}

#parentDiv2 {
  background-color: blue;
}

#targetDiv2 {
  background-color: red;
  position: sticky;
  top: 12em;
  left: 2em;
  width: 10em;
}
```
`position: sticky`に設定時に`top`、`left`、`bottom`、`right`を設定すると、`top`は、親の`div`タグからのオフセットで配置されました。`right`は無視され、この動作は、「position:stickyとtop、leftの動作」と同じでした。
`bottom`、`right`は設定されても無視されており、この動作は、「position:relativetop、left、bottom、rightの動作」と同じでした。

# おわりに
今回、`position`の値を色々変更し、どのような動作になるかを確認しました。
実際に試してみることで、説明に記載のあることが理解できてよかったと思いました。