スタックされた固定ヘッダーを試すときはCSSのposition: sticky;が便利


# 概要
* 画面のスクロールに追従せず画面上に要素が固定されるいわゆる「固定ヘッダー」を実現するには、 __position: stickey__ が便利。
* topやz-indexおよびHTMLの構造化か組み合わせれば積み重なったような効果も簡単に実現出来る。
* デスクトップも含めると対応が完全ではない（参考[CSS position:sticky](https://caniuse.com/#feat=css-sticky)）のが弱点だけど、実装が容易さから工数が確保しづらいモバイルアプリとか、UIのプロトタイプ作成なら採用していってもいいと思う

# こんな感じ
position stickyを使うと、ナビゲーション・年・月・日の順でタイトルが積み上がる表示をcssだけで実現出来ます。

[![https://gyazo.com/7d6faf14485f230438980b50b2fc257f](https://i.gyazo.com/7d6faf14485f230438980b50b2fc257f.gif)](https://gyazo.com/7d6faf14485f230438980b50b2fc257f)

# 基本
position: stickyにより固定ヘッダーを簡単に体感する構成は下記の通りです。

```test.html
<div class='large-box'>
</div>
<div class='calendar-box'>
  <div class='nav sticky'>ナビ</div>
</div>
<div class='large-box'>
</div>

```

```test.css
.large-box {
  height: 1000px;
  background-color: blue;
}
.calendar-box {
  background-color: red;
  height: 1000px
}
.nav {
  background-color: blue;
}
.sticky {
  postion: sticky; // 固定させたい箇所に指定する
  top: 0; // 固定させたい場所を書く
}
```

上記コードを表示させるとこのようになります。

[![https://gyazo.com/f8abba5949c3722c26cb49f0580a22cb](https://i.gyazo.com/f8abba5949c3722c26cb49f0580a22cb.gif)](https://gyazo.com/f8abba5949c3722c26cb49f0580a22cb)


stickyによる固定の仕組みを一言で説明すると、「 __固定したい箇所__ にpostion: sticky;を指定すると __親要素箇所__ がページ上に見えている限り、 __固定したい箇所__ は指定の位置（ __top: xx;__ ）以上に動かず固定るることができる。」ということです。

上記gifアニメーションだと固定したい箇所と親要素箇所が以下の通り対応します。

* 固定したい箇所（.stickey箇所（白））
* 親要素箇所（.calendar-box箇所（青））


普通の要素（.large-box箇所（白））はスクロールと連動して動きます。

一方、 __固定したい箇所__ は途中までにスクロールと連動しますが、ページ最上部（ __top: 0__ ）に固定されます。

また、更にスクロールさせます。

  __固定したい箇所__ は __親要素箇所__ であるが画面に表示されている間は、引き続きページ上部に固定されたままです。しかし、 __親要素箇所__ が画面から消えそうになるところで動き始め、最終的には、 __親要素箇所__ とともにページがからスクロールアウトされます。


# 応用（固定位置をスタックさせる）
冒頭に表示させたGIFアニメーションのように、固定したい要素を複数種類使うなど、ページ最上部ではなく、重ねて表示したい場合があります。（今回の例は年/月/日それぞれのタイトル）。この場合下記を考慮すれば実現出来ます。

* CSS
	* z-index
	* top

さらに、同じく冒頭に表示させたGIFアニメーションのように、日のタイトルのみ固定の解除/更新したい場合は下記を考慮すればよいです。
* HTML
	* 文章を構造する

## コード

```test1.html
<div class='header-box'>
  <h1>ヘッダー部分</h1>
</div>
<div class='calendar-box'>
  <div class='nav sticky'>ナビ top: 0; z-index: 4;</div>
  <div class='year-box'>
    <h2 class='year-title sticky'>2017年 top: 40px; z-index: 3;</h2>
    <div class='content-box'>コンテンツ</div>
    <div class='month-box'>
      <h3 class='month-title sticky'>11月 top: 80px; z-index: 2;</h3>
      <div class='content-box'>コンテンツ</div>
      <div class='day-box'>
        <h4 class='day-title sticky'>30日 top: 120px; z-index: 1;</h4>
        <div class='content-box'>コンテンツ</div>
      </div>
    </div>
    <div class='month-box'>
      <h3 class='month-title sticky'>12月 top: 80px; z-index: 2;</h3>
      <div class='content-box'>コンテンツ</div>
      <div class='day-box'>
        <h4 class='day-title sticky'>1日 top: 120px; z-index: 1;</h4>
        <div class='content-box'>コンテンツ</div>
      </div>
      <div class='day-box'>
        <h4 class='day-title sticky'>2日 top: 120px; z-index: 1;</h4>
        <div class='content-box'>コンテンツ</div>
      </div>
      <div class='day-box'>
        <h4 class='day-title sticky'>3日 top: 120px; z-index: 1;</h4>
        <div class='content-box'>コンテンツ</div>
      </div>
      <div class='day-box'>
        <h4 class='day-title sticky'>4日 top: 120px; z-index: 1;</h4>
        <div class='content-box'>コンテンツ</div>
      </div>
    </div>
  </div>
  
</div>

<div class='footer-box'>
  <h1>フッター部分</h1>
</div>
```

```test2.css
h2, h3, h4 {
  margin: 0;
  border: solid 1px;
}

.header-box {
  height: 200px;
  background-color: blue;
}
.footer-box {
  height: 400px;
  background-color: blue;
}
.calendar-box {
  background-color: red;
  padding: 5px
}
.year-box {
  background-color: pink;
  padding: 5px;
}
.month-box {
  background-color: purple;
  padding: 5px;
}
.day-box {
  background-color: yellow;
  padding: 5px;
}
.content-box {
  height: 100px;
  background-color: green;
}

.sticky {
  position: sticky;
  background-color: white;
}
.nav {
  top: 0;
  z-index: 4;
  height: 40px;
}
.year-title {
  top: 40px;
  z-index: 3;
}
.month-title {
  top: 80px;
  z-index: 2;
}
.day-title {
  top: 120px;
  z-index: 1;
}


```

## 説明

```（抜粋）test2.css
.nav {
  top: 0;
  z-index: 4;
  height: 40px;
}
.year-title {
  top: 40px;
  z-index: 3;
}
.month-title {
  top: 80px;
  z-index: 2;
}
.day-title {
  top: 120px;
  z-index: 1;
}
```

### top
topは要素を固定する位置です。よって、積み重なったような効果を出したい場合は、固定させる位置をtopの数値でずらせば良いです。
上記例では、ナビは0、年は40px, 月は80px, 日は120pxの位置に固定させています。

### z-index
スクロールアウトを自然な見た目にするためには、指定した方が良いです。積み重なった要素の内、下に固定させる要素はz-indexを小さく（逆に上に固定させるモノは大きく）すれば良いです。
上記例ではナビは4、年は3, 月は2, 日は1を指定しています。

### 構造化
一部だけ更新させる（上記例では日など）場合は親子を意識しながら、HTMLを構造化すれば良いです。
構造化といっても、難しい話ではなく、年の子要素に月、月の子要素に日を書いてやれば良いです。
たぶん普通にHTMLを書いていれば自然と構造化されているはずなので、問題ないと思います。
もしわからなかったら、上記HTMLを見ながら試行錯誤してみてください。

# 所感
試行錯誤が発生するプロトタイプの作成時の固定ヘッダーの実現ならこれ一択。

javascript書くとHTMLへ手をいれたり、コード量がムダに増えるから。


本番で使うかは、迷うところ。個人的には、モバイルに限った小さいプロジェクトなら採用してもいいとおもう。対応していないばあいでも該当要素がスクロールアウトするだけでページが破綻するわけではないし。（leftとかrightとかで固定したい場合除く）

## おまけ
アプリに応用するとこんなかんじ

[![https://gyazo.com/999cea1d90b1d2fae51fe8f0f29e7da2](https://i.gyazo.com/999cea1d90b1d2fae51fe8f0f29e7da2.gif)](https://gyazo.com/999cea1d90b1d2fae51fe8f0f29e7da2)