position: sticky;で固定ヘッダをらくらく実装

# 実装

1. 固定させたい要素に`position: sticky;`を付与する
2. 固定させる位置`top: 0;`を指定する

footerの場合は`bottom: 0;`とすれば下に固定されます。

```html:HTML
<body>
  <header class="ly_header">ヘッダ</header>
  <main class="ly_main">メインコンテンツ</main>
  <footer class="ly_footer">フッタ</footer>
</body>
```

```css:CSS
.ly_header {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
}
```

<p class="codepen" data-height="450" data-theme-id="dark" data-default-tab="css,result" data-user="heeroo-ymsw" data-slug-hash="oNzmwvV" style="height: 450px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="fixed-header">
  <span>See the Pen <a href="https://codepen.io/heeroo-ymsw/pen/oNzmwvV">
  fixed-header</a> by heeroo-ymsw (<a href="https://codepen.io/heeroo-ymsw">@heeroo-ymsw</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

# 実装時のポイント

## stickyの機能の仕方

`sticky`を指定した要素は、それを内包するコンテナ内でのみ固定されます。
つまり、前述の例でいえば、`body`内で固定されていることになります。

以下の例を見れば分かりやすいかと思います。

```html:HTML
<div class="bl_contents">
  <div class="bl_contents_item bl_contents_item__sticky">スティッキーアイテム</div>
  <div class="bl_contents_item">普通のアイテム</div>
</div>
<div class="bl_contents">
  <p>hogehoge fugafuga</p>
</div>
```

```css:CSS
.bl_contents_item__sticky {
  position: sticky;
  top: 0;
}
```

<p class="codepen" data-height="450" data-theme-id="dark" data-default-tab="css,result" data-user="heeroo-ymsw" data-slug-hash="bGwzrwK" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="sticky-sample1">
  <span>See the Pen <a href="https://codepen.io/heeroo-ymsw/pen/bGwzrwK">
  sticky-sample1</a> by heeroo-ymsw (<a href="https://codepen.io/heeroo-ymsw">@heeroo-ymsw</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

`bl_contents_item__sticky`クラスを指定した要素は、それを内包する`bl_contents`内でのみスティッキーを発揮することがお分かりいただけたと思います。

## 要素1つのみを内包する場合はstickyが機能しない

前述の内容を理解すれば当たり前だろと言いたくなるかもしれませんが、以下のような場合はstickyが機能しません。

```html:HTML
<div class="bl_contents">
  <div class="bl_contents_item bl_contents_item__sticky">スティッキーアイテム</div>
</div>
```

この場合、stickyアイテムには兄弟要素がないため、stickyしたくてもする場所がありません。
よって、うまく機能しないということになります。

## 対応ブラウザ

[Can I use](https://caniuse.com/css-sticky)によると、ほぼ全ての主要ブラウザは対応しています。
Safariではベンダープレフィックスを加える必要がありますので、以下のように記述します。

```css:prefix
.stickyItem {
  position: -webkit-sticky;
  position: sticky;
}
```

# position: fixed;との違い

`position: fixed;`でもヘッダ固定はできますが、大きな違いとしては、ページレイアウト内にその要素のための空白を用意してくれないということです。

実際に見れば違いは一目瞭然です。
一番最初の例を用いて、`position: fixed;`にするとこうなります。

![スクリーンショット 2021-01-18 19.40.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924363/5fef3931-234f-bded-2a16-cad04c63e9b5.png)

`fixed`を使うと、固定したい要素のwidthを指定したり、メインコンテンツにかぶらないようにmarginとったりなど、いろいろと気をつかわなければいけないことが発生します。
そのような点で`sticky`は簡素に記述ができ、便利です。

# まとめ

`sticky`の動きをテキストで説明するならば、以下の特徴を持っているといえます。

- `relative`や`static`のように、ページレイアウト内にその要素のための空間が作られる
- `fixed`のようにビューポートの同じ場所にぴたっとくっつく
- `relative`な親要素を持つ`absolute`のようにそれを内包する親要素にとどまる

# 参考文献

[CSS Position Sticky - How It Really Works! | by Elad Shechter](https://elad.medium.com/css-position-sticky-how-it-really-works-54cd01dc2d46)
[position - CSS: カスケーディングスタイルシート | MDN](https://developer.mozilla.org/ja/docs/Web/CSS/position)