JavaScript

【サンプルあり】JavaScript12行でアコーディオンパネルを実装する

ハロワ、ぽじぱん(@posipan999)です🌍

今回はネイティブJavaScript12行でアコーディオンパネルを実装する方法を紹介します。

ぽじぱん!

レツゴー✊

サンプル

パネルをクリックすると、隠れていた中身がアニメーションしながら表示されます。
ちゃっかり「+」アイコンもアニメーションさせています。

See the Pen Accordion by POSIPAN (@posipan) on CodePen.

解説

HTML

アコーディオンパネル1個分のHTMLです。

クリック領域(.accordion_ttl)と表示領域(.accordion_cnt)は隣接させてください。

<dl class="accordion">
  <dt class="accordion_ttl">アコーディオンだよ1</dt>
  <dd class="accordion_cnt">
    <p>見っかちゃった😜</p>
  </dd>
</dl>

CSS

アコーディオン部分のCSSです。SCSSで記述しています。

.accordion {
  max-width: 500px;
  padding: 0 15px;
  margin: 0 auto;
  
  .accordion_ttl {
    position: relative;
    background: #180680;
    color: #fff;
    font-size: 16px;
    padding: 15px;
    border-bottom: 1px solid #fff;
    cursor: pointer;
    &:before,
    &:after {
      content: "";
      display: block;
      position: absolute;
      top: 50%;
      right: 15px;
      transform: translate(0, -50%);
      width: 14px;
      height: 2px;
      background: #fff;
      transition: 0.2s ease transform;
    }
    
    &:after {
      transform: translate(0, -50%) rotate(-90deg);
    }
    
    &.active {
      &:after {
        transform: translate(0, -50%) rotate(0deg);
      }
    }
  }
  .accordion_cnt {
    padding: 0 15px;
    line-height: 1.5;
    background: #e4f681;
    max-height: 0;
    overflow: hidden;
    transition: 0.2s ease max-height;
    p {
      margin: 15px 0;
    }
  }
}

以下はアコーディオンパネルのクリック領域です。
クリックできることがわかるように、cursor: pointer;を指定してあげると親切です。

「+」アイコンは疑似要素:before, :afterで作り、パネルがクリックされた時にクラス.activeを付与し、疑似要素:afterが回転されるようにしています。

また、transitionでアニメーションさせています。

.accordion_ttl {
    position: relative;
    background: #180680;
    color: #fff;
    font-size: 16px;
    padding: 15px;
    border-bottom: 1px solid #fff;
    cursor: pointer;
    &:before,
    &:after {
      content: "";
      display: block;
      position: absolute;
      top: 50%;
      right: 15px;
      transform: translate(0, -50%);
      width: 14px;
      height: 2px;
      background: #fff;
      transition: 0.2s ease transform;
    }
    
    &:after {
      transform: translate(0, -50%) rotate(-90deg);
    }
    
    &.active {
      &:after {
        transform: translate(0, -50%) rotate(0deg);
      }
    }
  }

こちらは表示領域の部分です。
max-height: 0;overflow: hidden;で表示領域を完全に隠しています。
アニメーションさせるためにtransitionのプロパティにはmax-heightを指定しています。

 .accordion_cnt {
    padding: 0 15px;
    line-height: 1.5;
    background: #e4f681;
    max-height: 0;
    overflow: hidden;
    transition: 0.2s ease max-height;
    p {
      margin: 15px 0;
    }
  }

JavaScript

document.querySelectorAll()でパネル要素を取得しており、この中にはノードリスト(配列みたいなやつ)が入っています。

IE、Edge対策でノードリストをArray.fromで配列に変換し、forEachで処理しています。

ぽじぱん!

IE…IEめ!

ちなみにノードリストは配列と似ていますが、似て非なるもので配列の処理で使用するmapメソッドなどは使えません。

詳しい処理内容はコメントに記載しています。

// ノードリストを配列に変換
const accTtls = Array.from(document.querySelectorAll('.accordion_ttl'));

accTtls.forEach((item) => {
  // itemは.accordion_ttlを指す
  // 各itemにクリックイベントを付与
  item.addEventListener('click', function() {
    // クリックされたらクラス.activeを付与
    // thisはitemを指す
    this.classList.toggle('active');
    // クリックしたitemの隣接要素を変数に代入(.accordion_cnt)
    const accCnt = this.nextElementSibling;

    // .accordion_cntにmax-heightの値があったら
    if (accCnt.style.maxHeight) {
      // max-heightの値をnullにする。0にしてしまうと値が存在することになり、
      // アコーディオンは1回しか機能しない
      accCnt.style.maxHeight = null;
    } else {
      // .accordion_cntにmax-heightの値がなければ、scrollHeightの値を設定
      // scrollHeightは、あふれて画面上に表示されない部分を含めた要素の高さを取得するプロパティ
      // 読み取り専用のプロパティであり、値を変更することはできない。
      accCnt.style.maxHeight = accCnt.scrollHeight + 'px';
    }
  });
});

おわりに

コードを俯瞰してみると、アコーディオンパネルの実装はHTMLの構造、CSS設定、JavaScriptの処理、全てに気を使わなければならない印象ですね🤘