Webサイトでよく使われるアコーディオンメニュー。高さが動的に変わる要素のアニメーションは、かつて max-height などで力技で実装されることが多く、アニメーションの速度が不自然になるのが悩みの種でした。
今回は CSS Gridの grid-template-rows を活用し、高さの計算不要でスムーズに開閉するアコーディオンの作り方を解説します。
アコーディオン(完成品)
See the Pen Untitled by keiichisawai (@sawakei) on CodePen.
コード
HTML
<div class="accordion">
<div class="accordion__item">
<button type="button" class="accordion__header">
アコーディオン1
<span class="accordion__icon"></span>
</button>
<div class="accordion__content">
<div class="accordion__body">
ここにはアコーディオン1のコンテンツが入ります。テキストや画像などを配置できます。
</div>
</div>
</div>
<div class="accordion__item">
<button type="button" class="accordion__header">
アコーディオン2
<span class="accordion__icon"></span>
</button>
<div class="accordion__content">
<div class="accordion__body">
ここにはアコーディオン2のコンテンツが入ります。テキストや画像などを配置できます。
</div>
</div>
</div>
</div>CSS
.accordion {
overflow: hidden;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
.accordion__item {
border-bottom: 1px solid #e0e0e0;
}
.accordion__item:last-child {
border-bottom: none;
}
.accordion__header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 16px 20px;
font-weight: bold;
color: #333;
cursor: pointer;
outline: none;
background: #f9f9f9;
border: none;
transition: background-color 0.2s;
}
.accordion__icon {
width: 10px;
height: 10px;
border-right: 2px solid #666;
border-bottom: 2px solid #666;
transform: rotate(45deg);
transition: transform 0.3s;
}
.accordion__item.is-open .accordion__icon {
transform: rotate(-135deg);
}
.accordion__content {
display: grid;
grid-template-rows: 0fr; /*ポイント1*/
padding: 0 20px;
background-color: #fff;
transition: /*ポイント1*/
grid-template-rows 0.3s,
padding 0.3s;
}
.accordion__body {
overflow: hidden;
}
.accordion__item.is-open .accordion__content {
grid-template-rows: 1fr; /*ポイント1*/
padding: 16px 20px;
}JavaScript
document.addEventListener('DOMContentLoaded', () => {
const headers = document.querySelectorAll('.accordion__header');
headers.forEach((header) => {
header.addEventListener('click', () => {
const item = header.closest('.accordion__item');
const allItems = document.querySelectorAll('.accordion__item');
allItems.forEach((el) => {
if (el !== item) {
el.classList.remove('is-open');
}
});
item.classList.toggle('is-open');
});
});
});解説
高さの指定にgrid-template-rowsを使う
ここが一番重要な所だと思います(ポイント1)
下にコンテンツが展開するアニメーションを実装しようと、height:0からheight:autoとしてtransiton:height 0.3s;としてもtransitionは効かないのです。
そこで、grid-template-rowsを代わりに使います
.accordion__content {
display: grid;
grid-template-rows: 0fr;
padding: 0 20px;
background-color: #fff;
transition:
grid-template-rows 0.3s,
padding 0.3s;
}
.accordion__body {
overflow: hidden;
}
.accordion__contentに display:grid; を指定し、通常時はgrid-template-rows:0fr;(行の高さを0にする)にします。
transitionにgrid-template-rowsを指定します。
なお、overflow: hidden;を指定しないと、高さが0の指定でも中身が見えてしまうので、忘れずにしましょう。
.accordion__item.is-open .accordion__content {
grid-template-rows: 1fr;
}展開時には、grid-template-rows: 1fr;を指定します。



