CSSとjQueryでアコーディオンを実装する|detailsで作る方法も
CSSとjQueryでアコーディオンメニューを実装する方法を解説します。
結論から書くと、いま新しく作るならHTMLの <details> と <summary> だけで作れます。JavaScriptもjQueryも要りません。キーボード操作とスクリーンリーダーへの対応も最初から備わっています。
既存サイトにjQueryが入っている場合や、開閉の挙動を細かく制御したい場合は、この記事のjQuery版が使えます。両方の作り方を載せるので、状況に合うほうを選んでください。
アコーディオンメニューの作成例
今回作成するアコーディオンメニューです。
See the Pen
アコーディオンメニュー by りん@エンジニア (@rinblog0408)
on CodePen.
アコーディオンの基本構造を作成する
HTMLの準備
まず、アコーディオンを実装するための基本的なHTML構造を作成します。以下は、3つのセクションからなるアコーディオンの例です。各セクションには見出しとコンテンツが含まれます。
<div class="accordion">
<div class="accordion-section">
<div class="accordion-header">セクション1の見出し</div>
<div class="accordion-content">
セクション1のコンテンツがここに入ります。
</div>
</div>
<div class="accordion-section">
<div class="accordion-header">セクション2の見出し</div>
<div class="accordion-content">
セクション2のコンテンツがここに入ります。
</div>
</div>
<div class="accordion-section">
<div class="accordion-header">セクション3の見出し</div>
<div class="accordion-content">
セクション3のコンテンツがここに入ります。
</div>
</div>
</div>
CSSを使ってアコーディオンのスタイリングを行う
CSSの適用
アコーディオンのスタイリングを行います。以下のCSSコードは、基本的なスタイルを設定するもので、デザインに合わせてカスタマイズできます。
/* アコーディオンセクションのスタイル */
.accordion-section {
border: 1px solid #ddd;
margin-bottom: 10px;
}
/* アコーディオンヘッダーのスタイル */
.accordion-header {
background-color: #f1f1f1;
padding: 10px;
cursor: pointer;
}
/* アコーディオンコンテンツのスタイル */
.accordion-content {
display: none;
padding: 10px;
}
/* アクティブなアコーディオンのスタイル */
.active {
display: block;
}
jQueryを使ってアコーディオンの動作を追加する
jQueryの導入
jQueryを使用して、アコーディオンを動的に操作します。以下のコードをHTMLファイル内に挿入します。
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
$(document).ready(function() {
$('.accordion-header').on('click', function() {
const $header = $(this);
const $content = $header.next('.accordion-content');
const isOpen = $header.hasClass('active');
// いったんすべて閉じる
$('.accordion-content').slideUp();
$('.accordion-header').removeClass('active').attr('aria-expanded', 'false');
// 閉じていたものだけを開く(開いていたものはそのまま閉じる)
if (!isOpen) {
$header.addClass('active').attr('aria-expanded', 'true');
$content.slideDown();
}
});
});
</script>
開いている項目をもう一度押しても閉じないとき
結論:「すべて閉じる」処理と slideToggle() を続けて書くと、開いている項目を押したときに閉じてから開き直してしまいます。
slideUp() はアニメーションなので、実行した直後はまだ閉じ切っていません。その状態で slideToggle() を呼ぶと「今は開いている」と判定され、もう一度開いてしまうことがあります。
上のコードでは、クリック前の状態を isOpen に控えてからすべて閉じ、閉じていた場合だけ開くようにしています。これで、開いている項目を押せば確実に閉じます。
キーボードで操作できるようにする
結論:<div> のままではキーボードで操作できません。見出し部分を <button> にしてください。
<div class="accordion-header"> はクリックには反応しますが、Tabキーでフォーカスできず、Enterキーでも開きません。マウスが使えない人には操作できない状態になります。
<div class="accordion-section">
<button type="button" class="accordion-header" aria-expanded="false" aria-controls="panel1">
セクション1の見出し
</button>
<div class="accordion-content" id="panel1">
セクション1のコンテンツがここに入ります。
</div>
</div>
<button> にするとブラウザ標準の見た目が付くので、CSSで打ち消します。
.accordion-header {
display: block;
width: 100%;
text-align: left;
border: none;
font: inherit;
background-color: #f1f1f1;
padding: 10px;
cursor: pointer;
}
aria-expanded は、開いているかどうかをスクリーンリーダーに伝える属性です。上のJavaScriptで開閉に合わせて切り替えています。
JavaScriptを使わずにdetailsで作る
結論:HTMLの <details> と <summary> を使えば、CSSもJavaScriptも書かずにアコーディオンになります。キーボード操作とスクリーンリーダー対応も最初から入っています。
<details name="faq">
<summary>セクション1の見出し</summary>
<p>セクション1のコンテンツがここに入ります。</p>
</details>
<details name="faq">
<summary>セクション2の見出し</summary>
<p>セクション2のコンテンツがここに入ります。</p>
</details>
ポイントは name 属性です。同じ name を付けた <details> は排他的になり、1つ開くと他が自動で閉じます。この記事のjQuery版と同じ動きが、属性1つで実現できます。
見た目を整えるCSSはこれだけです。
details {
border: 1px solid #ddd;
margin-bottom: 10px;
}
summary {
background-color: #f1f1f1;
padding: 10px;
cursor: pointer;
}
details > *:not(summary) {
padding: 0 10px 10px;
}
detailsに開閉アニメーションを付ける
結論:::details-content 擬似要素で中身の高さを遷移させると、スライドしながら開きます。
/* height: auto へのアニメーションを許可する */
:root {
interpolate-size: allow-keywords;
}
details::details-content {
height: 0;
overflow: hidden;
transition: height 0.3s, content-visibility 0.3s;
transition-behavior: allow-discrete;
}
details[open]::details-content {
height: auto;
}
interpolate-size: allow-keywords は、height: 0 から height: auto へのアニメーションを可能にする指定です。これが無いと、高さが分からないため一瞬で開きます。
transition-behavior: allow-discrete は、閉じるアニメーションの最中も中身を表示したままにするための指定です。これが無いと、閉じ始めた瞬間に中身が消えます。
対応状況は Chromium 系のブラウザのみです(2026年9月時点)。ただし未対応のブラウザでも、アニメーションが付かないだけでアコーディオンとしては正しく動きます。そのまま書いて問題ありません。
どちらの作り方を選ぶか
結論:新しく作るなら <details>、既存サイトに手を入れるならjQuery版です。
▼2つの作り方の比較
| details / summary | CSS + jQuery | |
|---|---|---|
| JavaScript | 不要 | 必要 |
| キーボード操作 | 最初から対応 | buttonにする必要がある |
| スクリーンリーダー | 最初から対応 | aria属性を自分で付ける |
| 1つだけ開く動作 | name 属性1つ |
JavaScriptで制御 |
| 開閉アニメーション | Chromium系のみ | 全ブラウザで動く |
| 細かい挙動の制御 | しづらい | 自由にできる |
アニメーションが必須要件でなければ <details> を選んでください。書く量が減るうえに、アクセシビリティの対応漏れが起きません。開閉に合わせて他の処理を走らせたい、といった要求が出てきた段階でJavaScriptを足せば十分です。
要素の表示・非表示の切り替え方そのものを整理したい場合は、jQueryでドロップダウンメニューを実装する5つの方法もあわせてどうぞ。同じ考え方でメニューの開閉を作れます。
要素を辿る処理でつまずいたら、jQueryで親要素を取得する方法に .closest() の使い方をまとめています。
▼HTML/CSS/JavaScriptの学習本を探してる方はこちらの記事をどうぞ