🕌

【JS】アコーディオンをVanilla JS でやってみる

2022/12/01に公開

概要

前回同様にjQueryからVanillaJSへの切り替えとして、アコーディオンを忘備録としてメモ。

実装

サンプルとして、以下のような感じです。

html


  <div class="accordion">
    <h2 class="accordion__ttl">タイトル1</h2>
    <div class="accordion__cnt">
      <p>ここはコンテンツ</p>
    </div>
    <h2 class="accordion__ttl">タイトル2</h2>
    <div class="accordion__cnt">
      <p>ここはコンテンツ2</p>
      <p>ここはコンテンツ2</p>
      <p>ここはコンテンツ2</p>
    </div>
    <h2 class="accordion__ttl">タイトル3</h2>
    <div class="accordion__cnt">
      <p>ここはコンテンツ3</p>
    </div>
  </div>

Javascriptでクリックしたタイトルの次のコンテンツ要素をアコーディオンの対象とするため「accordion__ttl」と「accordion__cnt」を隣合わせにしています。

CSS(SCSS)

.accordion {
  &__ttl {
    background-color: #ffff00;
    padding: 5px;
    cursor: pointer;
    transition: background-color 0.3s;
    &:hover {
      background-color: #ff0000;
    }
    &.is-active {
      background-color: #ff0000;
    }
  }
  &__cnt {
    height: 0;
    overflow: hidden;
    transition: 0.2s ease height;
  }
  &__inner{
    padding:20px;
  }
}

クラス「accordion__cnt」がコンテンツの部分だが、display:noneにするのではなく、高さ(height)を0にする。コンテンツの内容がはみ出るので、overflow: hiddenで隠すようにする。

アコーディオンのアニメーションさせるのに、transitionで高さ(height)を指定する。

Javascript

const acc_ttl=Array.from(document.querySelectorAll(".accordion__ttl"));

for(let i=0; i< acc_ttl.length; i++){
  let ttl=acc_ttl[i];
  let content=ttl.nextElementSibling;
  ttl.addEventListener("click",()=>{
    ttl.classList.toggle("is-active");
    if (content.style.height) {
      content.style.height = null;
    } else {
      content.style.height = content.scrollHeight + 'px';
    }
  });
}

querySelectorAllでタイトルとなる部分を取得。
アコーディオンで表示するコンテンツはnextElementSiblingで取得。
ele.nextElementSiblingele要素の次の要素が取得できる読み取り専用のプロパティ。
クリックイベントでは、タイトルをクリックしたらtoggleis-activeのクラスを切り替える。

今回のポイントとなるアコーディオンの部分は、content.scrollHeightである。
ele.scrollHeightは読み取り専用のプロパティで、はみ出た要素(overflowなど)など画面上に表示されていないコンテンツを含む要素の内容の高さ取得できる。
scrollHeightの値は、素のpaddingは含みますが、marginは含まれない。

このcontent.scrollHeightを使うのですが、まずはコンテンツ要素の高さ(height)を調べるのだが初期値はCSSで0にしているため、content.scrollHeightで高さを設定する。ちゃんと「px」の値もつける。

次にクリックしたときはコンテンツ要素の高さ(height)が設定されてるので、その値を「null」にしてあげる。
これでアコーディオンの完了となる。。

まとめ

以下のサイトを参考にさせていただきました。
https://zenn.dev/antez/books/6da596a697aa86/viewer/c21f46#element.scrollwidth-%2F-scrollheight

https://developer.mozilla.org/ja/docs/Web/API/Element/scrollHeight
https://syncer.jp/javascript-reference/element/nextelementsibling

Discussion