CSSだけで簡単にドロワーメニュー(ハンバーガーメニュー)を作る

**ハンバーガーアイコンの☓になる動き、横からメニューが出てくる動き、メニューが出てるときはメインエリアを暗くすることまで、すべてCSSのみで実装可能。**

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="css,result" data-user="himeka223" data-slug-hash="PoYPOPy" 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="drawer menu">
  <span>See the Pen <a href="https://codepen.io/himeka223/pen/PoYPOPy/">
  drawer menu</a> by himeka223 (<a href="https://codepen.io/himeka223">@himeka223</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

#解説

CSSのみで作るドロワーメニューの動きは、**inputタグの`checkbox`で制御している。**

* **チェックがされた場合…　メニュー横から出現、アイコンを☓に、メインエリアを暗く。**
* **チェックがはずれた場合… すべてもとに戻る。**

##`checkbox` と `label` の連動

**`checkbox` を `label` と連動させ、
`label`のクリックで、`checkbox`にチェックが入るように。**

```html:hrader.html
<!-- checkbox自体は非表示 -->
<input class="l-drawer__checkbox" id="drawerCheckbox" type="checkbox" >
<!-- ハンバーガーアイコン -->
<label class="l-drawer__icon" for="drawerCheckbox">
  <span class="l-drawer__icon-parts"></span>
</label>
<!-- 背景を暗く -->
<label class="l-drawer__overlay" for="drawerCheckbox"></label>
```

###アイコンとの連動
`input`タグの**`id="drawerCheckbox"`**と、`label`タグの**`for="drawerCheckbox"`**で**同じ値を設定することで、`input`と`label`を紐付け、連動をさせている。**
###暗くなる背景との連動
**1つの`input`の`checkbox`に複数`label`を連動**できるので、背景を暗くするエリアを`label`とし、**`for="drawerCheckbox"`**で、連動させ、ここをクリックしてもチェックが外れるようにしている。

###`checkbox`の非表示
**`label`に連動させることで、`checkbox`の表示は不要なので、`display: none`で非表示にしておく。**


##ハンバーガーアイコン

アイコンもCSSで実装している。

```html:header.html
<!-- ハンバーガーアイコン -->
<label class="l-drawer__icon" for="drawerCheckbox">
  <span class="l-drawer__icon-parts"></span>
</label>
```

```scss:l-drawer.scss

// ハンバーガーアイコン
&__icon{
  cursor: pointer;
  display: block;
  width: 56px;
  height: 60px;
  position: fixed;
  right: 0;
  // ハンバーガーアイコンの中の線
  &-parts,
  &-parts:before,
  &-parts:after{
    background-color: #000;   
    display: block;
    width: 26px;
    height: 2px;
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    margin: auto;
  }
  &-parts:before,
  &-parts:after{
    content: " ";
  }
  &-parts:before{
    top: 16px
  }
  &-parts:after{
    top: -16px
  }
}
```

###`label`
ハンバーガーアイコンの外枠

* アイコンの**大きさ**を決め**ブロック要素**にする。
* `position: fixed`で、**位置を、ブラウザ自体に固定**する。（今回は右上に固定するため、`right: 0`指定）
* `cursor: pointer;`で**ホバー時のカーソルを矢印でなく、指マーク**にする。

###`span`（`label`の子要素）
ハンバーガーアイコンの三本線部分。
**`span`自体で、真ん中の線**を作り、**`span`の`after`と`before`の疑似要素で、で上の線と下の線**を作っている。

* 線1本の**長さ・太さを`width`と`height`**で決める。色は`background-color`で指定。
* **`position: absolute;`と`margin: auto`で`label`の中の上下中央揃え**にする。
* 上下の線`:after`と`:before`は**疑似要素なので、`content: " "`**を指定。
* 上下の線の位置を、**上は`top: -16px`と下は`top: -16px`**というように、移動させることで、三本線に。

##オーバーレイ
メニューが開いてるときは、メインエリアを暗くする。

```scss:l-drawer.scss
// ドロワーメニュー開いた時のメインエリアを暗く
&__overlay{
  background: #000;
  opacity: 0;
  // display: none; //opacity: 0;で非表示はできているため、display: none;は削除
  pointer-events: none; //ポインタの動作全部無効化
  width: 100%;
  height: 100%;
  position: fixed;
  top: 0;
  right: 0;
}
```
~~* **メニューが開かれる前は非表示**にするため**`opacty: 0`と`display: none;`を設定する~~
* **`width: 100%;`、`height: 100%;`**を指定し、メインエリア全体にかかるように。
* `position: fixed;`でブラウザに固定表示。


:writing_hand_tone1:　08/22 コメントにて下記ご指摘を頂きました。ありがとうございます。

* `pointer-events: none;`でポインタの動作を無効化する。
* `opacity: 0;`で非表示はできているため、`display: none;`の記載はいらない。
 

##メニュー

```scss:l-drawer.scss
// ドロワーメニュー
&__menu{
  background: #ffffff;
  color: #000;
  max-width: 100%;
  width: 320px;
  height: 100vh;
  overflow-y: auto; //スクロール
  -webkit-overflow-scrolling: touch; //スクロール（SP）
  position: fixed;
  top: 0;
  right: -320px;
}
```

* メニューが見えづらいので背景色を指定。
* `width`でメニューの幅、`height`でメニューの高さの指定。**`100vh`とすることでブラウザの高さ分の値**が取れる。
* **`overflow-y: auto;`と`-webkit-overflow-scrolling: touch;`を指定して、メニュー内のみスクロール**できるようにする。
* `position: fixed;`でブラウザ自体に固定。
* **`right: -320px`でメニュー幅分、右端からさらにに移動**させることで、クリック前はメニューを隠す。

##`:checked ~ `で、クリック後のスタイルを指定
`checkbox`に対して、**`:checked`**をつけると、**チェックボックスにチェックが入ってる時だけの指定**が出来る。
`~`セレクタは、**同じ階層で、後に出てくる要素すべて**を指定する。

この２つを組み合わせ、`:checked ~ `と指定すると、**チェックボックスにチェックが入ってる時、同階層であとに出てくる要素**への指定ができる。

今回は、上で説明した、**ハンバーガーアイコン、オーバーレイ、メニューのクリック後のスタイル**を設定する必要がある。

###クリック後のハンバーガーアイコン

```scss:l-drawer.scss
// ハンバーガーアイコン
.l-drawer__icon{
  .l-drawer__icon-parts{
    background: transparent;
  }
  .l-drawer__icon-parts:before{
    -webkit-transform: rotate(-45deg);
    transform: rotate(-45deg);
    top: 0;
  }
  .l-drawer__icon-parts:after{
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg);
    top: 0;
  }
}
```
* 真ん中の線は、`background: transparent;`で背景を透過させ見えなくする。
* 上下の線は、`top: 0;`で位置を戻し、`transform: rotate(-45deg);`で、それぞれ45°回転させる。

###クリック後のオーバーレイ

```scss:l-drawer.scss
// メインエリアを暗くする
.l-drawer__overlay {    
  opacity: 0.3;
  pointer-events: auto; //ポインタの動作デフォルトに戻す
}
```
~~* `display: block;`と`opacity: 0.3;`で表示させる~~

:writing_hand_tone1:　08/22 コメントにて下記ご指摘を頂きました。ありがとうございます。

* `pointer-events: none;`でポインタの動作を無効化してたのを`auto`にしてデフォルトに戻す。
* `opacity: 0.3;`で表示はできているため、`display: block;`の記載はいらない。

###クリック後のメニュー

```scss:l-drawer.scss
// メニューをだす
.l-drawer__menu {
  right: 0;
}
```

* 左にマイナスで隠してため、`right: 0`に指定して、位置を右端に揃える

##`z-index`で重なりを調整

```scss:l-drawer.scss
// z-indexの指定（1がメインエリア）
&__icon{
  z-index: 4;
}
&__menu{
  z-index: 3;
}
&__overlay{
  z-index: 2;
}
```

* メインエリアガ一番下として、**`オーバーレイ`→`メニュー`→`ハンバーガーアイコン`**となるように調整
* まとめて書くことで調整しやすくする。

##`transition`で動きをスムーズに

```scss:l-drawer.scss
// 動きをスムーズに
&__icon-parts,
&__icon-parts:after,
&__icon-parts:before,
&__overlay,
&__menu{
  -webkit-transition: all .7s ;
  transition: all .7s ;
}
```

* 同じスピードでと動くようにまとめて記載。
* `all`ですべての変化するプロパティに、`.7s`で0.7秒かけて変化する指定。


#まとめ
inputのcheckboxやradioを使えばjsを使わなくてもCSSでできることが増えそう。
同じような考えでモーダルも実装可能である。


#参考サイト

[ドロワーやモーダルをCSSだけで実現する方法 \| HPcode](https://haniwaman.com/css-modal-drawer/)
[CSSだけで簡単！ハンバーガーメニューの作り方（スマホ対応）](https://saruwakakun.com/html-css/reference/nav-drawer)