アコーディオンメニュー

自分用の備忘録に作りました。
pureなJSでアコーディオンメニューを実装し、一応簡単な形ですがレスポンシブ対応してるので、参考にしてください。

## 完成図

![camp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/1c034285-8598-ab82-c166-abf58c1e1e1d.gif)

## コード

※注意点としては、コードはPCファーストになってます。

```html:html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>navber</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <!-- Font Awesome -->
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.1/css/all.css" integrity="sha384-vp86vTRFVJgpjF9jiIGPEEqYqlDwgyBgEF109VFjmqGmIY/Y4HV4d3Gp2irVfcrp" crossorigin="anonymous">
  <!-- Google Font -->
  <link rel="preconnect" href="https://fonts.gstatic.com">
  <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;700&display=swap" rel="stylesheet">
  <!-- CSS -->
  <link rel="stylesheet" href="./css/style.css">
  <!-- JS -->
  <script src="./js/main.js"></script>
</head>
<body>
  <!-- header -->
  <header>
    <h1>NavberTest</h1>
    <p>~ navber test web app ~</p>
  </header>
  <!-- navigation for pc -->
  <nav class="pc-nav">
    <ul>
      <li><a href="#">menu1</a></li>
      <li><a href="#">menu2</a></li>
      <li><a href="#">menu3</a></li>
    </ul>
  </nav>
  <!-- navigation for sp -->
  <nav class="sp-nav">
    <ul>
      <li><a href="#">menu1</a></li>
      <li><a href="#">menu2</a></li>
      <li><a href="#">menu3</a></li>
    </ul>
  </nav>
  <!-- bars icon -->
  <div class="bars" id="spNavToggle"><i class="fas fa-bars"></i></div>
</body>
</html>
```

```css:css
@charset "UTF-8";
/* reset */
*{
  margin: 0;
  padding: 0;
  font-family: 'Noto Sans JP', sans-serif;
  line-height: 1;
}
ul{
  list-style: none;
}
a{
  text-decoration: none;
}
/* header */
header{
  background: #000000;
  color: #ffffff;
  padding: 10px;
  margin-bottom: 20px;
}
/* navigation for pc */
nav.pc-nav{
  max-width: 960px;
  margin: 0 auto;
}
nav.pc-nav ul{
  display: flex;
}
nav.pc-nav li{
  width: 100%;
  border-right: 1px solid #ffffff;
}
nav a{
  display: block;
  line-height: 44px;
  text-align: center;
  width: 100%;
  background: #000000;
  color: #ffffff;
}
/* navigation for sp */
nav.sp-nav{
  /* 768px以上では非表示にする。 */
  display: none;
}
nav.sp-nav li{
  border-top: 1px solid #ffffff;
  transition: 0.3s;
  /* デフォルトでは高さを０。そして０からはみ出た分を非表示にする。 */
  height: 0;
  overflow: hidden;
}
nav.sp-nav li.active{
  /* JSで表示させるときのCSS。overflowを初期値のvisibleに書き換える。 */
  height: 44px;
  overflow: visible;
}
/* bars icon */
.bars{
  /* 768px以上では非表示にする。 */
  display: none;
  width: 50px;
  height: 50px;
  border: 2px solid #ffffff;
  border-radius: 5px;
  color: #ffffff;
  text-align: center;
  font-size: 35px;
  /* positionでbodyの右上に配置*/
  position: absolute;
  top: 10px;
  right: 10px;
}
.bars i{
  /* アイコンを縦の真ん中に配置 */
  line-height: 50px;
}
/* under 767px size */
@media screen and (max-width: 767px){
  header{
    margin: 0;
  }
  /* ipad以下ではpc版のnavを非表示。sp版のnavとbarsボタンを表示させる。 */
  nav.pc-nav{
    display: none;
  }
  nav.sp-nav{
    display: block;
  }
  .bars{
    display: block;
  }
}
```

```javascript:js
window.onload = function(){
  // 変数宣言
  const spNavToggle = document.getElementById('spNavToggle');
  const spNavLi = document.querySelector('.sp-nav').querySelectorAll('li'); //.sp-nav内のliを全て取得し、配列化。
  // クリックイベント
  spNavToggle.onclick = function(){
    // 配列をアイテム1つずつ処理。liにactiveクラスを付与している。
    spNavLi.forEach((liTag) => {
      liTag.classList.toggle('active');
    })
  }
}
```

## ポイント
#### html
・PC版とSP版でnavを２つ書いてます。
→この方がコード量は多少増えますが、メンテが楽です。
#### css
・上記理由でnavが２つあるので、出来るだけ共通のプロパティはまとめ、それ以外は`nav.pc-nav`,`nav.sp-nav`と使い分けてCSSを適用しています。
・アコーディオンメニューの肝である`nav.sp-nav li`の`height: 0;`,`overflow: hidden;`
→これがメインの部分です。<font color="red">**初期値は非表示にしたいのですが、`display:none;`ではなく、**</font>アコーディオンメニューの演出の都合上、上記のような書き方になっています。その後ここに<font color="red">**`active`クラスが追加されることで**</font>`height: 44px;`,`overflow: visible;`が適用され、<font color="red">**アコーディオンのように徐々に膨らむような動きになります。**</font>

#### JS
ここは特に、難しいことは無いのですが、`forEach`で繰り返し処理をしたいので、<font color="red">**配列として扱える`querySelector`を使っています。**</font>

## 最後に
改めてpureなJSってコード書くのめんどいなって思いました。でもプログラミングしてるなって感覚になって出来ると楽しいですねｗ

今後もこう言った小ネタ的なものをガンガン上げていきたいと思います。お疲れ様でした。