今回はWebサイトやLPでよく使われるアコーディオンメニューの実装方法を解説します。
HTMLとCSSだけでできるものと、JavaScriptが入ったものそれぞれの解説をします。
ぜひ参考にしてみてください。
アコーディオンメニューとは?
アコーディオンメニューは、クリックやタップで表示・非表示が切り替わるメニュー形式で、一般的にサイドバーやQ&Aコーナーなどで使われます。
このメニュー形式では、見出し部分をクリックすると、コンテンツが展開され、もう一度クリックすると折りたたまれます。
WebサイトやLPでは、ユーザーの視認性やユーザー体験の向上を目的として、導入されます。
HTMLによる実装
一見難しそうなアコーディオンメニューですが、HTMLとCSSだけでも簡単に実装できます。
まずはHTMLを記述します。
<details>
<summary>accordion title</summary>
<div class="contents">
accordion contents
</div>
</details>
detailsタグを使い、中にsummaryタグを入れます。タイトルはsummaryタグの中に記述します。(Q&AではQの部分です。)その下にはdivタグで内容を記述します。(Q&AだとAの部分です。)
次は、最低限のCSSを記述します。
details {
summary {
cursor: pointer;
padding: 1.5em 2em;
}
.contents {
padding: 2em;
}
}
これで完成です。
これを複数並べ、文字色や背景色を変えると以下のようになります。
See the Pen accordion_html by Bunta (@bbunta) on CodePen.
JavaScriptなしの問題点
HTMLとCSSだけで実装する場合は非常に簡単ですが、以下のような問題点があります。
- 動きが滑らかではない。(カクカクしている)
- 中身をクリックしてもメニューが閉じない。
- 他のアイテムを開いた時に、今開いているアイテムが閉じない。
少しリッチなサイトにしたい場合は、JavaScriptは必要になります。
JavaScriptありの場合
まずはHTMLを記述します。
<dl>
<dt class="acHeader">accordion title</dt>
<dd><div>accordion contents</div></dd>
</dl>
dl,dt,ddタグで実装しています。
全てdivタグでも作れますが、アクセシビリティを意識する場合はこちらをおすすめします。
また、クラス名は一箇所だけつけています。
後に記述するJavaScriptでもこの要素だけ取得するようにします。
続いてCSSです。
dl {
dt {
position: relative;
padding: 1.5em 2em;
cursor: pointer;
dd {
opacity: 0;
visibility: hidden;
max-height: 0;
transition: 0.3s;
div {
padding: 2em;
}
}
}
今回もできる限りシンプルにしています。
先ほどとの大きな違いは、ddを非表示にしている点です。
JavaScriptで表示、非表示を切り替えるためです。
では、JavaScriptです。
JavaScriptは少し長いので、分けて解説します。
const headers = document.querySelectorAll(".acHeader");
headers.forEach((header) => {
header.addEventListener("click", () => toggleAccordion(header));
const content = header.nextElementSibling;
if (content) {
content.addEventListener("click", () => toggleAccordion(header));
}
});
まずはacHeaderを取得します。複数ある場合を想定してquerySelectorAllを使っています。
それをforEachループで一つずつ回しています。
ここでのheaderはdtです。dtをクリックするとtoggleAccordion関数を実行するようにプログラミングしています。クリックすると開いて、もう一度クリックすると閉じるようにするためです。
次はcontentです。header.nextElementSiblingで、headerの次の要素を取得しています。今回のケースではddです。dtと同じく、クリックするとtoggleAccordion関数が実行するようにしています。コンテンツをクリックした場合もメニューを閉じるようにするためです。
続いてtoggleAccordion関数を設定します。
const item = header.parentElement;
const content = header.nextElementSibling;
if (item.classList.contains("active")) {
item.classList.remove("active");
content.style.maxHeight = "";
content.style.opacity = "0";
content.style.visibility = "hidden";
} else {
item.classList.add("active");
content.style.maxHeight = content.scrollHeight + "px";
content.style.opacity = "1";
content.style.visibility = "visible";
}
itemはheader.parentElementなので、今回のケースではdlです。contentは先ほどと同じddです。
その下は条件分岐です。もしdlにactiveクラスがついていれば、ddは非表示にするように設定しています。それ以外の場合、つまりdlにactiveクラスが付いていない場合は、ddを表示するようにしています。
これだけでもいいですが、今回はさらに、他のメニューをクリックした場合に、今開いているメニューを閉じるコードも付け加えておきます。
toggleAccordion関数の中に追記します。
headers.forEach((hdr) => {
const itm = hdr.parentElement;
const cnt = hdr.nextElementSibling;
if (itm !== item && itm.classList.contains("active")) {
itm.classList.remove("active");
if (cnt) {
cnt.style.maxHeight = "";
cnt.style.opacity = "0";
cnt.style.visibility = "hidden";
}
}
});
もし、クリックした要素以外にactiveクラスがついている場合は、activeクラスを外して、ddは非表示にするといったプログラミングをしています。
これらをまとめると以下のようになります。
おまけでcssで作った矢印もつけておきます。
See the Pen accordion_js by Bunta (@bbunta) on CodePen.
クリックするとアコーディオンメニューが開き、他のメニューをクリックすると、開いているメニューが閉じるのが確認できます。
まとめ
今回は、アコーディオンメニューの実装方法をHTMLとCSSのみのパターンと、そこにJavaScriptを加えたパターンを紹介しました。
JavaScriptは慣れないと難しい部分もありますが、少しずつ読み解いていけば、徐々に理解できるようになります。
今後も当サイトでは様々なコードやプログラミングの実装方法などを紹介していきますので、ぜひ楽しみにしていてください。
フロントエンドエンジニアやコーダー向けに、以前書いた以下の記事もおすすめです。こちらもぜひご覧ください。