複数項目のうち、常に一つだけ開くことができるアコーディオンUIです。
クリックすると `grid-template-rows` を `0fr` ⇔ `1fr` に切り替えることでスムーズな開閉アニメーションが動作し、JavaScriptはクラスの付け外しのみで簡単に実装できます。FAQや手順説明などに最適です。
このアコーディオンUIでは、CSSの display: grid と grid-template-rows を利用して開閉アニメーションを実現しています。height: auto ではトランジションできないため、0frから1frに切り替えることで中身の高さに応じてスムーズに展開できます。JavaScriptはクリック時に.is-openクラスを切り替えるだけなので、処理が軽くメンテナンス性も高い構造です。また、複数の質問を同時に開ける仕様にしているため、ユーザーは必要な情報を一度に比較できます。
<div class="accordion" id="accordion">
<div class="accordion__item">
<button class="accordion__trigger">見出しA</button>
<div class="accordion__panel">
<div class="accordion__panel-inner">
<div class="accordion__content">コンテンツAがここに入ります。</div>
</div>
</div>
</div>
<div class="accordion__item">
<button class="accordion__trigger">見出しB</button>
<div class="accordion__panel">
<div class="accordion__panel-inner">
<div class="accordion__content">コンテンツBがここに入ります。</div>
</div>
</div>
</div>
<div class="accordion__item">
<button class="accordion__trigger">見出しC</button>
<div class="accordion__panel">
<div class="accordion__panel-inner">
<div class="accordion__content">コンテンツCがここに入ります。</div>
</div>
</div>
</div>
</div>
.accordion__item {
border: 1px solid #e5e7eb;
border-radius: 8px;
overflow: hidden;
background: #fff
}
.accordion__item+.accordion__item {
margin-top: 12px
}
.accordion__trigger {
width: 100%;
text-align: left;
display: block;
padding: 16px 18px;
font-size: 16px;
line-height: 1.4;
border: 0;
cursor: pointer;
background: #e6f4ff;
transition: filter .2s
}
.accordion__trigger:hover {
filter: brightness(0.98)
}
.accordion__panel {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows .28s ease;
border-top: 1px solid #e5e7eb
}
.accordion__item.is-open .accordion__panel {
grid-template-rows: 1fr
}
.accordion__panel-inner {
overflow: hidden
}
.accordion__content {
padding: 14px 18px 18px;
font-size: 15px;
color: #333;
background: #e6fffa
}
@media (max-width:480px) {
.accordion__trigger {
padding: 14px;
font-size: 15px
}
.accordion__content {
padding: 12px 14px 14px;
font-size: 14px
}
}
const accordion = document.getElementById('accordion');
const items = accordion.querySelectorAll('.accordion__item');
accordion.addEventListener('click', (e) => {
const btn = e.target.closest('.accordion__trigger');
if(!btn) return;
const item = btn.parentElement;
const isOpen = item.classList.contains('is-open');
items.forEach(i => i.classList.remove('is-open'));
if(!isOpen) item.classList.add('is-open');
});