CSS Stickyでサイドバーの下端を追従させる

ハマったけどググってもわからず、どうにか自己解決したのでメモ書きを残します。
お忙しい方は一番下だけ見てください。

## 普通に組む

サイドバーを追従させるのに便利なcssの `position: sticky;`
今時のcssであれば、`flex` を使って下記のように実装することが多いかと思います。
(flexを使っていない方のお役には立てません。すみません。がんばってください。)

```HTML:
<div class="container">
  <div class="sidebar">...sidebar...</div>
  <div class="main">...main contents...</div>
</div>
```

```css:
.container {
  display: flex;
  align-items: flex-start;
}

.sidebar {
  width: 30%;
  position: -webkit-sticky;
  position: sticky;
  top: 20px;
}

.main {
  width: 70%;
}
```

上記のコードでスクロールするとこんなかんじになります。
→→→→→

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45187/491361cb-b782-d6b6-aae9-976c987b9b56.png)

IE以外のブラウザであれば、基本的にはこれで問題ないはずです。
IEで動かずとも、サイドバーが追従しないというだけなので無理に対応する必要はありません。

## 縦幅が長いサイドバーの場合

しかし、**サイドバーの縦幅が画面サイズを上回る場合、**問題が発生します。
スクロールした際にサイドバーの上端が固定されるので、最下部にたどり着くまで下端が見えないのです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45187/d80f0d98-277f-abf9-8bf8-5f22dae01585.png)

広告など重要度の低いコンテンツがはみ出る分には問題ないのですが、
(ちょうどQiitaのように)ページ内の見出し毎にナビゲーションが置かれている場合などは特に困りものです。
Qiitaはサイドバーの中をスクロールさせるようにしています(※2020年10月現在)が、
ユーザーによってはスクロールできることに気付かない場合もあるでしょう。

どうにかスマートに解決できないものか…（cssだけで…）


## 下端で固定する

`position: sticky;` は上端( `top` )だけでなく、上下左右の4方向で追従させることができます。
であれば、下端を追従させれば解決する気がします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45187/56069744-4381-c743-f5dc-6afe14287f00.png)

```css:
.container {
  display: flex;
  align-items: flex-start;
}

.sidebar {
  width: 30%;
  position: -webkit-sticky;
  position: sticky;
  bottom: 20px; /* ここを変えた */
}

.main {
  width: 70%;
}
```

しかし、**これでは動きませんでした。** (stickyが効かない状態になります)

## 解決策

`align-items` のデフォルトの値 `stretch` を上書きするために指定していた
`flex-start;` を `flex-end` に変更します。

```css:
.container {
  display: flex;
  align-items: flex-end; /* ここ！！ */
}

.sidebar {
  width: 30%;
  position: -webkit-sticky;
  position: sticky;
  bottom: 20px;
}

.main {
  width: 70%;
}
```

### 解説

`sticky` でコンテンツを下端に追従させるためには、
**そのコンテンツが画面下から出てくる必要がある** みたいです。(多分。)
おそらく、左にあるものを右揃えにしようとしても同様に動かないのではないかと思われます。
(まあ、横スクロール追従なんてほぼ使いませんが…)

デフォルトの `align-items: stretch;` ではサイドバーとメインコンテンツの縦幅が揃ってしまうため、
そもそも `sticky` が動きません。

そのため `flex-start` を指定して上揃えにしているのですが、
これを `flex-end` にして下揃えにすることで、サイドバーが下方向から出てくるようになります。
これで画像の様に動くようになりました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45187/56069744-4381-c743-f5dc-6afe14287f00.png)


## IE対策

はじめの実装では一旦無視したIEなのですが、
この実装で無視をすると、 `flex-end` によってサイドバーが画面下に配置されたまま動かなくなります。
これはさすがに不便です。
`sticky`自体をIEで動かすことは不可能なので、
cssハックを利用し、IEではサイドバーが上に配置されるよう変更します。

```css:
.container {
  display: flex;
  align-items: flex-end;
}

/* for IE */
@media (-ms-high-contrast: none), (-ms-high-contrast: active) {
  .container {
    align-items: flex-start;
  }
}

.sidebar {
  width: 30%;
  position: -webkit-sticky;
  position: sticky;
  bottom: 20px;
}

.main {
  width: 70%;
}
```

※ IEでflexを使う場合、内容によってはうまく動かないことがあります。
実際に確認しながらprefixを付けるなどして対応しましょう。

## 完成品をもういちど

```HTML:
<div class="container">
  <div class="sidebar">...sidebar...</div>
  <div class="main">...main contents...</div>
</div>
```

```css:
.container {
  display: flex;
  align-items: flex-end;
}

@media (-ms-high-contrast: none), (-ms-high-contrast: active) {
  .container {
    align-items: flex-start;
  }
}

.sidebar {
  width: 30%;
  position: -webkit-sticky;
  position: sticky;
  bottom: 20px;
}

.main {
  width: 70%;
}
```

無事、IEでも違和感のない表示が実現できました！
記述量も少なめで、jsのライブラリを導入するよりとてもリーズナブルです。

他によい実装方法があれば、ぜひおしえてください :raised_hand: