アコーディオンFAQを
Vanilla.js(純粋なJavaScript)で実装する機会があったので備忘録として記載
アコーディオンFAQをこれから実装する人の参考になれば幸いです。
なぜjQueyをなぜ使わないのか?
jQueryはInternet Explorer時代に一世を風靡したJavaScriptフレームワークで
純粋なJavaScriptを書くよりもスピード感を持って実装できる画期的なフレームワーク
Internet Explorerがサ終(サポート終了)になった今、
使うメリットがなくなり
スマホで反応しなかったり不具合が多数報告。
いつjQueryもサ終になるかわからないので、jQueryで実装することが返ってデメリットに感じている。
そこで、今回はVanilla.js(純粋なJavaScript)で実装することに
アコーディオンFAQ
See the Pen Untitled by 松村祐弥 (@lveklkok-the-vuer) on CodePen.
以下、使用しているコードです。
HTML
<div class="faq-item">
<div class="faq-question__wrap">
<h3 class="faq-question__title">ダミーテキスト</h3>
<span class="minus-icon"></span>
<span class="plus-icon"></span>
</div>
<div class="faq-answer__wrap">
<p class="faq-answer__title">ダミーテキスト</p>
<p class="faq-answer__text">ダミーテキスト</p>
</div>
</div><!-- faq-item end -->
<div class="faq-item">
<div class="faq-question__wrap">
<h3 class="faq-question__title">ダミーテキスト</h3>
<span class="minus-icon"></span>
<span class="plus-icon"></span>
</div>
<div class="faq-answer__wrap">
<p class="faq-answer__title">ダミーテキスト</p>
<p class="faq-answer__text">ダミーテキスト</p>
</div>
</div><!-- faq-item end -->
<div class="faq-item">
<div class="faq-question__wrap">
<h3 class="faq-question__title">ダミーテキスト</h3>
<span class="minus-icon"></span>
<span class="plus-icon"></span>
</div>
<div class="faq-answer__wrap">
<p class="faq-answer__title">ダミーテキスト</p>
<p class="faq-answer__text">ダミーテキスト</p>
</div>
</div><!-- faq-item end -->
これが今回使用したhtmlです。
質問項目を増やしたり減らしたりしたい人は
.faq-itemを調整してください。
CSS
.faq-item {
margin-top: 20px;
max-width: 720px;
margin-left: auto;
margin-right: auto;
border: 1px solid #0C89B7;
}
.faq-question__wrap {
position: relative;
background: #0C89B7;
padding: 10px 5px 10px 55px;
cursor: pointer;
}
.minus-icon {
position: absolute;
content: "";
width: 20px;
height: 3px;
background: #fff;
right: 20px;
top: 50%;
transform: translateY(-50%);
}
.plus-icon {
position: absolute;
content: "";
width: 20px;
height: 3px;
background: #fff;
right: 20px;
top: 50%;
transform: translateY(-50%) rotate(90deg);
transition: ease all 0.5s; /* 擬似要素のトランジションを追加 */
}
.plus-icon.active {
transform: translateY(-50%);
}
.faq-question__title {
font-weight: bold;
color: #FFF;
font-size: 20px;
position: relative;
}
.faq-question__title::before {
position: absolute;
color: #fff;
content: "Q";
top: 50%;
left: -35px;
transform: translateY(-50%);
}
.faq-answer__wrap {
background: #fff;
padding: 10px 5px 10px 55px;
transition: ease all 0.5s; /* 擬似要素のトランジションを追加 */
height: 0;
overflow: hidden;
padding-top: 0;
padding-bottom: 0;
}
.faq-answer__wrap.active {
height: auto;
padding: 10px 5px 10px 55px;
}
.faq-answer__wrap {
background: #fff;
opacity: 0;
padding: 10px 5px 10px 55px;
padding-top: 0;
padding-bottom: 0;
overflow: hidden;
transition: ease all 0.7s; /* 擬似要素のトランジションを追加 */
}
.faq-answer__wrap.active {
opacity: 1;
padding: 10px 5px 10px 55px;
}
.faq-answer__title {
position: relative;
font-weight: bold;
color: #0C89B7;
font-size: 20px;
color
}
.faq-answer__title::before {
position: absolute;
color: #0C89B7;
content: "A";
top: 50%;
left: -35px;
transform: translateY(-50%);
}
.faq-answer__text {
margin-top: 5px;
}
CSSです。
適宜変更してください。
JavaScript
document.addEventListener('DOMContentLoaded', function () {
const faqItems = document.querySelectorAll('.faq-item');
faqItems.forEach(item => {
const questionWrap = item.querySelector('.faq-question__wrap');
const answerWrap = item.querySelector('.faq-answer__wrap');
const plusIcon = item.querySelector('.plus-icon');
questionWrap.addEventListener('click', () => {
// 回答表示の切り替え
answerWrap.classList.toggle('active');
// アイコンの切り替え
plusIcon.classList.toggle('active');
});
});
});
これが今回使用したJavaScriptです。
JavaScriptの解説
HTMLの構造
このJavaScriptコードは、以下のようなHTML構造を持つアコーディオンを想定
HTML
<div class="faq-item">
<div class="faq-question__wrap">
<h3 class="faq-question__title">質問のタイトル</h3>
<span class="minus-icon"></span>
<span class="plus-icon"></span>
</div>
<div class="faq-answer__wrap">
<p class="faq-answer__title">回答のタイトル</p>
<p class="faq-answer__text">回答の内容</p>
</div>
</div>
- .faq-item が1つの質問と回答のセットになっています。
- .faq-question__wrap が質問部分を、.faq-answer__wrap が回答部分を囲っています。
- .plus-icon は質問が閉じているときに表示するアイコン、.minus-icon は質問が開いているときに表示するアイコンです。
JavaScriptの解説
- DOMContentLoadedイベント:
document.addEventListener('DOMContentLoaded', function () { // ... });
- DOMContentLoaded イベントは、HTMLドキュメントが完全に読み込まれて解析された後に発生します。このイベント内で処理を行うことで、HTML要素が確実に存在する状態でJavaScriptを実行できます。
- FAQアイテムの取得:
const faqItems = document.querySelectorAll('.faq-item');
- querySelectorAll(‘.faq-item’) を使用して、HTMLドキュメント内にある .faq-item クラスを持つすべての要素を取得し、faqItems に格納します。
- 各FAQアイテムへのイベントリスナー設定:
faqItems.forEach(item => { // ... });
- faqItems をループ処理し、各FAQアイテム (item) に対して以下の処理を行います。
- 要素の取得:
const questionWrap = item.querySelector('.faq-question__wrap'); const answerWrap = item.querySelector('.faq-answer__wrap'); const plusIcon = item.querySelector('.plus-icon');
- 現在のFAQアイテム (item) 内から、質問部分(.faq-question__wrap)、回答部分(.faq-answer__wrap)、プラスアイコン(.plus-icon)を取得し、それぞれ変数に格納します。
- クリックイベントリスナーの設定:
questionWrap.addEventListener('click', () => { // ... });
- 質問部分(questionWrap)にクリックイベントリスナーを設定します。クリックされると以下の処理が実行されます。
- 回答表示の切り替え:
answerWrap.classList.toggle('active');
- 回答部分(answerWrap)の active クラスを切り替えます。これにより、CSSで定義された active クラスのスタイルが適用・解除され、表示・非表示が切り替わります。
- アイコンの切り替え:
plusIcon.classList.toggle('active');
- プラスアイコン(plusIcon)の active クラスを切り替えます。これにより、CSSで定義された active クラスのスタイルが適用・解除され、アイコンの表示が切り替わります。
ポイント
- active クラスのスタイルはCSSで定義します。
- アコーディオンの開閉状態を初期表示と異なる状態にする場合は、JavaScriptで active クラスの追加・削除を調整します。