CSSのみで実装するハンバーガーメニュー

#はじめに
スマホ用ページなどでよく利用される、「ハンバーガーメニュー」をCSSのみで実装して見ます。
あくまで機能面の実装を目的としているので、デザイン面でのCSSは省略しています。

#基本のHTML構造
```html
<header class="header">
  <h1><a href="index.html">TITLE</a></h1>
  <div class="menu-trigger">
    開く
  </div>
  <nav id="top-nav" class="nav-menu">
    <ul>
      <li><a href="index.html">HOME</a></li>
      <li><a href="about.html">ABOUT</a></li>
      <li><a href="contact.html">CONTACT</a></li>
    </ul>
  </nav>
</header>
```

#ハンバーガーメニューの実装イメージ
![スクリーンショット 2020-06-02 10.01.41（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369388/1a55dee8-4a26-7e39-d41c-a588e5cb9651.png)

「開く」ボタンと「閉じる」ボタンを押すことでメニューの開閉をする簡単な構造になります。

## titleとmenuを両端に配置
```css
.header{
  display: flex;
  justify-content: space-between;
}
```
flexboxを使って、左右両端に配置します。

## nav-menuを右上に固定
```css
.header{
  position: relative;
}
.nav-menu{
  position: absolute;
  top: 0;
  right: 0;
}
```
position：absoluteを使って位置を固定しています。
その際、基準となるheaderにposition: relativeを設定します。

## メニュー開閉の仕組みを作る
メニュー開閉の仕組みは、ｃｓｓのtarget属性にて実装します。

```html
<header class="header">
  <h1><a href="index.html">TITLE</a></h1>
  <div class="menu-trigger">
    <a href="#top-nav">開く</a>
  </div>
  <nav id="top-nav" class="nav-menu">
    <a href="#!" class="menu-close">閉じる</a>
    <ul>
      <li><a href="index.html">HOME</a></li>
      <li><a href="about.html">ABOUT</a></li>
      <li><a href="contact.html">CONTACT</a></li>
    </ul>
  </nav>
</header>
```
aタブを用いて、対象のid属性を指定しています。
閉じるボタンの href="#!" は、ターゲットを外す目的で指定しています。

```css
.nav-menu:not(:target){
}
.nav-menu:target{
}
```
非表示のスタイルを　:not(:target)
表示スタイルを　:target に記述します。

## nav-menuを非表示にする
```css
.nav-menu:not(:target){
  opacity: 0;
  visibility: hidden;
}
```
opacityで透明度を０に、visibility: hiddenで非表示にしています。

## メニュー表示時、nav-menuを表示させる
```css
.nav-menu:target{
  opacity: 1;
  visibility: visible;
}
```
opacityで透明度を1に、visibility: visibleで表示しています。

## 開閉時のフェードイン・アウト

```css
.nav-menu:not(:target){
  transition: 1s;
}
.nav-menu:target{
  transition: 1s;
}
```
transitionでプロパティ変化の時間を指定しています。


## 閉じるボタンを右上に固定する
```css
.menu-close{
  position: absolute;
  top: 0;
  right: 0;
}
```
position：absoluteを使って位置を固定しています。

## 各要素の重なり具合を調整する
下から

* header(body)
* menu-trigger
* nav-menu

の順番で重なるようにz-indexを指定していきます

```css
.menu-trigger{
  position: relative;
  z-index: 2;
}
.nav-menu{
  z-index: 3;
  background: white;
}
```
z-indexは、positionプロパティが設定されていないと適応されないため、position: relativeを追記しています。
nav-menuは、menu-triggerを隠すため、背景色をつけています。

##ここまでのまとめ

```html
<header class="header">
  <h1><a href="index.html">TITLE</a></h1>
  <div class="menu-trigger">
    <a href="#top-nav">開く</a>
  </div>
  <nav id="top-nav" class="nav-menu">
    <a href="#!" class="menu-close">閉じる</a>
    <ul>
      <li><a href="index.html">HOME</a></li>
      <li><a href="about.html">ABOUT</a></li>
      <li><a href="contact.html">CONTACT</a></li>
    </ul>
  </nav>
</header>
```

```css
.header{
  display: flex;
  justify-content: space-between;
  position: relative;
}
.nav-menu{
  position: absolute;
  top: 0;
  right: 0;
  z-index: 3;
  background: white;
}
.nav-menu:not(:target){
  opacity: 0;
  visibility: hidden;
  transition: 1s;
}
.nav-menu:target{
  opacity: 1;
  visibility: visible;
  transition: 1s;
}
.menu-close{
  position: absolute;
  top: 0;
  right: 0;
}
.menu-trigger{
  position: relative;
  z-index: 2;
}
```

#レスポンシブ対応
PC版とスマホ版でCSSを切り替えます。

```html
<head>
 <meta name="viewport" content="width=device-width, initial-scale=1">
</head
```
cssにてメディアクエリを使用するため、headタグにてviewportを読み込みます。

PC版のスタイルは

```css
.header{
  display: flex;
  justify-content: space-between;
  position: relative;
}
.nav-menu{
  display: block;
}
.nav-menu ul{
  display: flex;
  justify-content: space-between;
}
.nav-menu li{
  padding-left: 10px;
}
.menu-close{
  display: none;
}
.menu-trigger{
  display: none;
}
```
で作られているものとして話を進めます。

## メディアクエリの実装
PCとスマホのCSSで異なる点を記述してみます。

```css
-- 共通 --
.header{
  display: flex;
  justify-content: space-between;
  position: relative;
}

.nav-menu{
-- PC --
  display: block;
-- スマホ --
  position: absolute;
  top: 0;
  right: 0;
  z-index: 3;
  background: white;
}

-- PC --
.nav-menu ul{
  display: flex;
  justify-content: space-between;
}
.nav-menu li{
  padding-left: 10px;
}

-- スマホ --
.nav-menu:not(:target){
  opacity: 0;
  visibility: hidden;
  transition: 1s;
}
.nav-menu:target{
  opacity: 1;
  visibility: visible;
  transition: 1s;
}


.menu-close{
-- PC --
  display: none;
-- スマホ --
  position: absolute;
  top: 0;
  right: 0;
}


.menu-trigger{
-- PC --
  display: none;
-- スマホ --
  position: relative;
  z-index: 2;
}
```
今回はスマホ版をデフォルトとし、PC版をメディアクエリで変更していきます。

```css
.header{
  display: flex;
  justify-content: space-between;
  position: relative;
}

.nav-menu{
  position: absolute;
  top: 0;
  right: 0;
  z-index: 3;
  background: white;
}
@media screen and (min-width: 1000px){
.nav-menu{
  display: block;
}
}

@media screen and (min-width: 1000px){
.nav-menu ul{
  display: flex;
  justify-content: space-between;
}
}

@media screen and (min-width: 1000px){
.nav-menu li{
  padding-left: 10px;
}
}

@media screen and (max-width: 1000px){
.nav-menu:not(:target){
  opacity: 0;
  visibility: hidden;
  transition: 1s;
}
}
@media screen and (max-width: 1000px){
.nav-menu:target{
  opacity: 1;
  visibility: visible;
  transition: 1s;
}
}


.menu-close{
  position: absolute;
  top: 0;
  right: 0;
}
@media screen and (min-width: 1000px){
.menu-close{
  display: none;
}
}

.menu-trigger{
  position: relative;
  z-index: 2;
}
@media screen and (min-width: 1000px){
.menu-trigger{
  display: none;
}
}
```
ｐｃ版のスタイルに対して、@media screen and (min-width: 1000px)にてCSSを変更しています。

.nav-menu:not(:target), .nav-menu:target に関してはスマホ版のみのスタイルなので、@media screen and (max-width: 1000px) にて指定してあります。

以上にてレスポンシブ対応が完了しました。
ブレークポイントを増やす場合は、適宜追加してください。