この記事では、CSS GridとJavaScriptを使って、スムーズなアコーディオンを実装する方法を解説します。
完成イメージ
- 初期状態では中身が非表示
- ボタンをクリックするとスムーズに展開
- +/− アイコンが切り替わる
- 閉じたときは元の位置にスクロール
See the Pen Untitled by watanabe (@web-sourcecode) on CodePen.
コードの全体
HTML
<div class="c-accordion js-accordion">
<div class="c-accordion__content">
<div class="c-accordion__content__inner">
<p>dammy text</p>
<p>dammy text</p>
<p>dammy text</p>
</div>
</div>
<button class="c-accordion__trigger js-accordion-trigger" type="button">
button<i class="c-accordion__trigger__icon"></i>
</button>
</div>
SCSS
.c-accordion {
&__content {
display: grid;
grid-template-rows: 0fr; // 高さゼロで非表示
opacity: 0;
transition: .36s grid-template-rows ease;
&__inner {
overflow: hidden;
}
.is-opened & {
grid-template-rows: 1fr; // 高さを自動に
opacity: 1;
}
}
&__trigger {
position: relative;
display: block;
cursor: pointer;
text-align: center;
font-weight: 600;
border-radius: 100vmax;
color: black;
border: 2px solid black;
background-color: #fff;
width: 300px;
margin: 20px auto 0;
font-size: 16px;
padding: 1em 0;
&__icon {
position: absolute;
top: 0;
right: 12px;
width: 44px;
height: 100%;
&::before,
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: black;
}
&::before {
width: 18px;
height: 2px; // 横線
}
&::after {
width: 2px;
height: 18px; // 縦線
}
.is-opened &::after {
opacity: 0; // 縦線を消して−にする
}
}
}
}
JavaScript
const items = document.querySelectorAll('.js-accordion');
items.forEach(item => {
const trigger = item.querySelector('.js-accordion-trigger');
if (trigger) {
trigger.addEventListener('click', function (e) {
e.stopPropagation();
const isActive = item.classList.contains('is-opened');
item.classList.toggle('is-opened');
if (isActive) {
item.scrollIntoView({ behavior: 'instant', block: 'start' });
}
});
}
});
ポイント
grid-template-rowsを使った高さアニメーションmax-heightより滑らかで、中身の高さが可変でも対応可能。- アイコンは
::beforeと::afterでCSSだけで描画。 - 縦線を消すだけで+→−に切り替え。
.is-openedクラスの付け外しでCSSの状態を切り替え- 閉じるときは
scrollIntoViewで元の位置までスクロール
応用例
1つだけ開くアコーディオンにする場合は以下を追加します。
items.forEach(item => {
const trigger = item.querySelector('.js-accordion-trigger');
if (trigger) {
trigger.addEventListener('click', e => {
e.stopPropagation();
items.forEach(i => i.classList.remove('is-opened')); // 全部閉じる
item.classList.add('is-opened'); // クリックしたものだけ開く
});
}
});
まとめ
アコーディオンはFAQやメニューに限らず、コンテンツの折りたたみにも応用できます。
CSS Gridを使えば、よりモダンで柔らかな動きを簡単に実現できます。





