ハロワ、ぽじぱん(@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の処理、全てに気を使わなければならない印象ですね🤘