ヘッダーを除いた要素だけでスクロールさせたい【HTML CSS】

# 目的
　「ヘッダーの幅をスクロールバーで縮めたくない」。
　ヘッダーを固定する方法に `position: fixed` を指定するという方法があるが、
このやり方では固定はできても「ヘッダーを除いた要素だけでスクロール」とはニュアンスが違ってしまう。
　要は以下のようなものを作りたい、という記事。
![スクリーンショット 2024-10-30 073827.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3922328/1bdc676d-62ac-43c4-334d-b01f143b22da.png)



# 結論から
　bodyに `height: 100%` を指定、
コンテンツ部分を `flex-grow: 1` でヘッダー・フッターを差し引いた高さに固定し、
`overflow-y: scroll` でコンテンツ部分だけをスクロールさせる。
　コメントアウト部分が要点。

```css:style.css
* {
    margin: 0 0;
    padding: 0 0;
}
body {
    overflow: hidden;
    height: 100%; /* 高さをブラウザ画面と同じにする */
    display: flex; /* frex-growのために指定 */
    flex-direction: column; /* flexはデフォで横並びになるので縦並びに指定 */
}
.header {
    height: 100px;
    min-height: 100px;
    background-color: blue;
}
.contents {
    flex-grow: 1; /* 親要素の高さ(幅)を埋めるようにストレッチさせる */
    overflow-y: scroll; /* この要素をスクロールさせる(autoでも可) */
    display: flex;
    flex-direction: column;
}
.box {
    height: 200px;
    min-height: 200px;
    display: flex;
    padding: 20px;
}
.item {
    flex-grow: 1;
    background-color: gray;
    font-size: 5em;
}
.footer {
    height: 100px;
    min-height: 100px;
    background-color: red;
}
```

```html:index.html
<html>
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="header">
        <h1>HEADER</h1>
    </div>
    <div class="contents">
        <div class="box">
            <div class="item">1</div>
        </div>
        <div class="box">
            <div class="item">2</div>
        </div>
        <div class="box">
            <div class="item">3</div>
        </div>
        <div class="box">
            <div class="item">4</div>
        </div>
        <div class="box">
            <div class="item">5</div>
        </div>
    </div>
    <div class="footer">
        <h1>FOOTER</h1>
    </div>
</body>
</html>
```



# HTMLの基本的なスクロールの仕組み

### デフォルトでの仕様
　body内の要素が画面(ブラウザ上の表示画面)の大きさを越えると画面全体のスクロールが有効になる。
　それ以外は親要素より子要素が大きくても、親要素から飛び出るだけで、まとめてbodyのスクロールに内包されるのがデフォルトでの仕様。

### 特定の要素内でスクロールさせるには
　親要素より子要素が大きい場合に、親要素内でスクロールさせたい場合は、親要素のstyleに `overflow: scroll` を指定する必要がある。
　これによって親要素の高さ(幅)の範囲内で子要素をスクロールさせる事ができる。
　`overflow` は縦方向と横方向別々に指定することも可能で、その場合は `overflow-x: hidden` `overflow-y: scroll` のように指定する。
　また、スクロールバーの幅だけ親要素の表示範囲が狭まるので注意が必要。
　スクロールバーのデザインを変更したり非表示にする事もできるが、今回は割愛。



# bodyのスクロールを無効にして高さを指定する

```css
body {
    overflow: hidden;
    height: 100%;
    display: flex;
    flex-direction: column;
}
```

- `overflow: hidden` ：要素の範囲外に出た部分を非表示にする
- `height: 100%` ：要素の高さをブラウザ画面の高さに指定
- `display: flex` ：子要素のfrex-growのために指定
- `flex-direction: column` ：flexはデフォで横並びになるので縦並びにするために指定

　これによってbodyのサイズをブラウザ画面全体に指定し、bodyでのスクロールを無効化する事ができる。

　今回は body に対して設定しているが、別に body じゃなくても問題無い。

:::note warn
(スマホ横向き表示とかで)ヘッダーやフッターが画面を占有しすぎると、
コンテンツ部分の表示の為の枠が潰れるので注意
→ height の単位を vh にするなどして対策可能
:::



# flex-grow: 1; によって要素を引き延ばす

```css
.contents {
    flex-grow: 1;
    overflow-y: scroll;
    display: flex;
    flex-direction: column;
}
```

- `flex-grow: 1` ：親要素の幅・高さを埋めるように要素を引き延ばす
- `overflow-y: scroll` ：縦方向のスクロールバーを表示させる

　`flex-grow: 1` によって、親要素の高さから、高さの確定している同じ階層の要素の高さの合計を引いた高さに設定される。
　例えば、親要素の高さが 720px、同じ階層の要素(header)の高さが 200px、同じ階層の要素(footer)の高さが 100px のとき、
残りの 420px が `flex-grow: 1` を設定した要素の高さとして設定される。
　 `flex-grow: 1` を設定している要素が2つ以上存在する場合は、等分になるように設定される。



# 横方向に並べて同じことをしたい場合
```css
body {
    overflow: hidden;
    height: 100%;
    display: flex;
    flex-direction: row;
}
```

- `flex-direction: row` ：column だった部分を row にするだけで横方向への配置になる