アコーディオンメニュー(haml,scss,javascript)


はじめに

タイトルについて記事にしました。
この記事で得る内容は以下の通りです。

・ CSSの基礎知識が増える
・ アコーディオンメニューの作り方について

例えば、こんな画面があったとします

手順

*説明に必要な所だけ記述しています

① アコーディオンメニューをクリックしたら、表示する場所を予め記述します
→ 今回、アコーディオンメニューが%aだとすると、.answer配下の%p fuga

index.haml
.wrapper
  .wrapper__text
    %i.far.fa-envelope-open
    %h2 よくある質問
  .wrapper__question
    %a
      %i.far.fa-question-circle
      %p hoge?
    .answer
      %p fuga

② ①で記述した要素をアコーディオンメニュークリック後に表示させたいので、display: none;で隠しておきます

index.scss
.answer {
  display: none;
}

③ アコーディオンメニューをクリックしたら.activeクラスをつけると想定して、display: block;を指定します

index.scss
.answer.active {
  display: block;
}

④ hamlにJavaScriptファイルを読み込む記述と、accordion.jsファイルを新規作成します

index.html
= javascript_pack_tag 'accordion'

⑤ accordion.jsに処理を記述します

accordion.js
const accordionMenu = document.querySelectorAll(".wrapper__question > a"); // アコーディオンメニュー発火部分をCSSのセレクタで要素を取得する変数

for (let i = 0; i < accordionMenu.length; i++) { // querySelectcorAllで要素を配列で取得して、変数"accordionMenu"の数だけ処理をfor文で繰り返す
  accordionMenu[i].addEventListener("click", function () {
    this.nextElementSibling.classList.toggle("active"); // イベントが起こっている要素の次のクラスを切り替える
  });
}

%aタグにhref属性があり、クリック後にページがリロードしてしまう場合は、以下のように記述します

accordion.js
const accordionMenu = document.querySelectorAll(".wrapper__question > a");

for (let i = 0; i < accordionMenu.length; i++) {
  accordionMenu[i].addEventListener("click", function (e) { // ファンクションに引数"e"(名前は自由)を持たせタグのイベントを取得する
    e.preventDefault(); // hrefのイベントをキャンセルする
    this.nextElementSibling.classList.toggle("active");
  });
}

アコーディオンメニューの機能自体はこれで完成していますが、右端の矢印を回転させる処理を記述します

⑦ accordion.js及び、index.scssを以下のように記述します

accordion.js
const accordionMenu = document.querySelectorAll(".wrapper__question > a");

for (let i = 0; i < accordionMenu.length; i++) {
  accordionMenu[i].addEventListener("click", function () {
    this.classList.toggle("active"); // クリックした要素(a)自体に"active"クラスを切り替える
    this.nextElementSibling.classList.toggle("active");
  });
}
index.scss
    a.active::after {
      transform: rotate(180deg);
    }

これでアコーディオンメニューをクリックしたら、矢印がクルクル回転する様になりました

参考(今回のコード)

index.haml
.wrapper
  .wrapper__text
    %i.far.fa-envelope-open
    %h2 よくある質問
  .wrapper__question
    %a
      %i.far.fa-question-circle
      %p hoge?
    .answer
      %p fuga
= javascript_pack_tag 'accordion'
index.scss
.wrapper {
  text-align: center;
  padding: 4rem 0;
  letter-spacing: 2px;
  &__text {
    i {
      font-size: 1.5rem;
      margin-right: -5px;
      vertical-align: 3px;
    }
    h2 {
      font-size: 1.75rem;
      font-weight: bold;
      display: inline-block;
    }
  }
  &__question {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-top: 3rem;
    a {
      font-size: 1.25rem;
      font-weight: bold;
      border: 1px solid #ddd;
      padding: 1rem 1.5rem;
      width: 70%;
      margin-bottom: 0.3rem;
      text-align: left;
      i {
        color: #016ea9;
        margin-right: -10px;
      }
      p {
        display: inline-block;
      }
    }
    a::after {
      content: "\02228";
      color: #ccc;
      float: right;
    }
    a:hover > p {
      text-decoration: underline;
    }
    .answer {
      width: 70%;
      text-align: left;
      padding: 1rem 1rem 2rem;
      display: none;
      p {
        font-weight: bold;
        color: #333;
      }
    }
    .answer.active {
      display: block;
    }
    a.active::after {
      transform: rotate(180deg);
    }
  }
}
accordion.js

const accordionMenu = document.querySelectorAll(".wrapper__question > a");

for (let i = 0; i < accordionMenu.length; i++) {
  accordionMenu[i].addEventListener("click", function () {
    this.classList.toggle("active");
    this.nextElementSibling.classList.toggle("active");
  });
}