アコーディオン
見出しのクリックで本文を滑らかに開閉するアコーディオン。max-heightアニメとaria属性で、FAQやヘルプの折りたたみ表示に使えます。
ライブデモ
使用例(お題: カフェ MOON BREW)
この技法を「カフェ MOON BREW」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- MOON BREW:店舗FAQをアコーディオンで折りたたみ表示 -->
<div class="cafe">
<header class="cafe__bar">
<span class="cafe__logo">☕ MOON BREW</span>
<nav class="cafe__nav"><a>MENU</a><a>STORE</a><a class="is-active">FAQ</a></nav>
</header>
<div class="cafe__faq">
<p class="cafe__eyebrow">よくあるご質問</p>
<h1 class="cafe__h1">ご来店の前に</h1>
<div class="acc">
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>席の予約はできますか?</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>2名様以上から公式サイトで前日までご予約いただけます。窓際のソファ席は人気のため、お早めの予約がおすすめです。</p></div>
</div>
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>豆の量り売りはありますか?</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>自家焙煎の中深煎り「ムーンブレンド」を100g単位で量り売りしております。挽き方もその場でお選びいただけます。</p></div>
</div>
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>Wi-Fiや電源は使えますか?</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>全席で無料Wi-Fiをご利用いただけます。電源はカウンター席とテラス席にご用意。混雑時は2時間制とさせていただきます。</p></div>
</div>
</div>
</div>
</div>
CSS
/* MOON BREW カフェ テーマ */
:root{
--cream:#f5ede1;
--brown:#2b1d12;
--amber:#c98a3b;
--line:#e3d6c2;
--muted:#7a6450;
}
*{box-sizing:border-box}
body{
margin:0;min-height:100vh;
font-family:"Hiragino Mincho ProN","Segoe UI",serif;
background:var(--cream);color:var(--brown);
}
.cafe{max-width:560px;margin:0 auto;padding:0 18px 24px}
.cafe__bar{
display:flex;align-items:center;justify-content:space-between;
padding:14px 4px;border-bottom:1px solid var(--line);
}
.cafe__logo{font-weight:700;letter-spacing:.06em}
.cafe__nav{display:flex;gap:14px;font-size:.78rem;letter-spacing:.1em;color:var(--muted)}
.cafe__nav a{cursor:pointer}
.cafe__nav .is-active{color:var(--amber);font-weight:700}
.cafe__faq{padding-top:18px}
.cafe__eyebrow{margin:0;font-size:.72rem;letter-spacing:.25em;color:var(--amber)}
.cafe__h1{margin:4px 0 16px;font-size:1.5rem;letter-spacing:.04em}
.acc{width:100%}
.acc__item{
background:#fffaf2;border:1px solid var(--line);
border-radius:12px;margin-bottom:10px;overflow:hidden;
transition:border-color .25s,box-shadow .25s;
}
.acc__item.is-open{border-color:var(--amber);box-shadow:0 6px 18px rgba(201,138,59,.12)}
.acc__head{
width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;
padding:15px 18px;background:none;border:none;cursor:pointer;
color:inherit;font:inherit;font-weight:600;text-align:left;
}
.acc__head:focus-visible{outline:2px solid var(--amber);outline-offset:-2px}
.acc__icon{
width:18px;height:18px;flex:none;fill:none;stroke:var(--amber);
stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;
transition:transform .3s ease;
}
.acc__item.is-open .acc__icon{transform:rotate(180deg)}
/* max-height アニメで滑らかに開閉 */
.acc__panel{max-height:0;overflow:hidden;transition:max-height .35s ease}
.acc__panel p{margin:0;padding:0 18px 16px;color:var(--muted);line-height:1.75;font-size:.9rem}
@media (prefers-reduced-motion:reduce){.acc__panel,.acc__icon{transition:none}}
JavaScript
// 各FAQ項目に開閉トグルを設定(1つだけ開くモード)
const items = document.querySelectorAll('[data-acc]');
items.forEach((item) => {
const head = item.querySelector('.acc__head');
const panel = item.querySelector('.acc__panel');
if (!head || !panel) return; // null安全
head.addEventListener('click', () => {
const willOpen = !item.classList.contains('is-open');
// すべて閉じてから対象だけ開く
items.forEach((other) => {
other.classList.remove('is-open');
const oh = other.querySelector('.acc__head');
const op = other.querySelector('.acc__panel');
if (oh) oh.setAttribute('aria-expanded', 'false');
if (op) op.style.maxHeight = null;
});
if (willOpen) {
item.classList.add('is-open');
head.setAttribute('aria-expanded', 'true');
panel.style.maxHeight = panel.scrollHeight + 'px'; // 実高さで展開
}
});
});
コード
HTML
<!-- アコーディオン:見出しをクリックすると本文が開閉する -->
<div class="acc">
<h2 class="acc__title">よくある質問</h2>
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>配送にはどれくらいかかりますか?</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>ご注文確定後、通常2〜4営業日でお届けします。離島・一部地域は追加日数をいただく場合があります。</p></div>
</div>
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>返品・交換はできますか?</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>到着後14日以内であれば未使用品に限り返品・交換を承ります。お問い合わせフォームからご連絡ください。</p></div>
</div>
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>支払い方法を教えてください</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>各種クレジットカード、コンビニ決済、銀行振込、主要なQRコード決済に対応しています。</p></div>
</div>
</div>
CSS
/* カラーとサイズをカスタムプロパティで管理 */
:root{
--bg:#0f172a;
--card:#1e293b;
--line:#334155;
--accent:#38bdf8;
--text:#e2e8f0;
--muted:#94a3b8;
--radius:14px;
}
*{box-sizing:border-box}
body{
margin:0;
min-height:100vh;
display:grid;
place-items:center;
padding:28px 16px;
font-family:"Segoe UI",system-ui,sans-serif;
color:var(--text);
background:radial-gradient(1200px 500px at 50% -10%,#1e3a5f,transparent),var(--bg);
}
.acc{width:min(440px,100%)}
.acc__title{
margin:0 0 16px;
font-size:1.15rem;
letter-spacing:.04em;
display:flex;align-items:center;gap:10px;
}
.acc__title::before{
content:"";width:8px;height:22px;border-radius:4px;
background:linear-gradient(var(--accent),#6366f1);
}
.acc__item{
background:var(--card);
border:1px solid var(--line);
border-radius:var(--radius);
margin-bottom:10px;
overflow:hidden;
transition:border-color .25s;
}
.acc__item.is-open{border-color:var(--accent)}
.acc__head{
width:100%;
display:flex;align-items:center;justify-content:space-between;gap:12px;
padding:16px 18px;
background:none;border:none;cursor:pointer;
color:inherit;font:inherit;font-weight:600;text-align:left;
}
.acc__head:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.acc__icon{
width:20px;height:20px;flex:none;
fill:none;stroke:var(--accent);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;
transition:transform .3s ease;
}
.acc__item.is-open .acc__icon{transform:rotate(180deg)}
/* max-height アニメで滑らかに開閉 */
.acc__panel{
max-height:0;overflow:hidden;
transition:max-height .35s ease;
}
.acc__panel p{
margin:0;padding:0 18px 18px;
color:var(--muted);line-height:1.7;font-size:.92rem;
}
@media (prefers-reduced-motion:reduce){
.acc__panel,.acc__icon{transition:none}
}
JavaScript
// 各アコーディオン項目に開閉トグルを設定
const items = document.querySelectorAll('[data-acc]');
items.forEach((item) => {
const head = item.querySelector('.acc__head');
const panel = item.querySelector('.acc__panel');
if (!head || !panel) return; // null安全
head.addEventListener('click', () => {
const willOpen = !item.classList.contains('is-open');
// 他の項目を閉じる(1つだけ開くモード)
items.forEach((other) => {
other.classList.remove('is-open');
const oh = other.querySelector('.acc__head');
const op = other.querySelector('.acc__panel');
if (oh) oh.setAttribute('aria-expanded', 'false');
if (op) op.style.maxHeight = null;
});
if (willOpen) {
item.classList.add('is-open');
head.setAttribute('aria-expanded', 'true');
// 実際の高さを与えて滑らかに展開
panel.style.maxHeight = panel.scrollHeight + 'px';
}
});
});
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「アコーディオン」の効果を追加してください。
# 追加してほしい効果
アコーディオン(UIコンポーネント)
見出しのクリックで本文を滑らかに開閉するアコーディオン。max-heightアニメとaria属性で、FAQやヘルプの折りたたみ表示に使えます。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- アコーディオン:見出しをクリックすると本文が開閉する -->
<div class="acc">
<h2 class="acc__title">よくある質問</h2>
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>配送にはどれくらいかかりますか?</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>ご注文確定後、通常2〜4営業日でお届けします。離島・一部地域は追加日数をいただく場合があります。</p></div>
</div>
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>返品・交換はできますか?</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>到着後14日以内であれば未使用品に限り返品・交換を承ります。お問い合わせフォームからご連絡ください。</p></div>
</div>
<div class="acc__item" data-acc>
<button class="acc__head" aria-expanded="false">
<span>支払い方法を教えてください</span>
<svg class="acc__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
</button>
<div class="acc__panel"><p>各種クレジットカード、コンビニ決済、銀行振込、主要なQRコード決済に対応しています。</p></div>
</div>
</div>
【CSS】
/* カラーとサイズをカスタムプロパティで管理 */
:root{
--bg:#0f172a;
--card:#1e293b;
--line:#334155;
--accent:#38bdf8;
--text:#e2e8f0;
--muted:#94a3b8;
--radius:14px;
}
*{box-sizing:border-box}
body{
margin:0;
min-height:100vh;
display:grid;
place-items:center;
padding:28px 16px;
font-family:"Segoe UI",system-ui,sans-serif;
color:var(--text);
background:radial-gradient(1200px 500px at 50% -10%,#1e3a5f,transparent),var(--bg);
}
.acc{width:min(440px,100%)}
.acc__title{
margin:0 0 16px;
font-size:1.15rem;
letter-spacing:.04em;
display:flex;align-items:center;gap:10px;
}
.acc__title::before{
content:"";width:8px;height:22px;border-radius:4px;
background:linear-gradient(var(--accent),#6366f1);
}
.acc__item{
background:var(--card);
border:1px solid var(--line);
border-radius:var(--radius);
margin-bottom:10px;
overflow:hidden;
transition:border-color .25s;
}
.acc__item.is-open{border-color:var(--accent)}
.acc__head{
width:100%;
display:flex;align-items:center;justify-content:space-between;gap:12px;
padding:16px 18px;
background:none;border:none;cursor:pointer;
color:inherit;font:inherit;font-weight:600;text-align:left;
}
.acc__head:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.acc__icon{
width:20px;height:20px;flex:none;
fill:none;stroke:var(--accent);stroke-width:2.2;stroke-linecap:round;stroke-linejoin:round;
transition:transform .3s ease;
}
.acc__item.is-open .acc__icon{transform:rotate(180deg)}
/* max-height アニメで滑らかに開閉 */
.acc__panel{
max-height:0;overflow:hidden;
transition:max-height .35s ease;
}
.acc__panel p{
margin:0;padding:0 18px 18px;
color:var(--muted);line-height:1.7;font-size:.92rem;
}
@media (prefers-reduced-motion:reduce){
.acc__panel,.acc__icon{transition:none}
}
【JavaScript】
// 各アコーディオン項目に開閉トグルを設定
const items = document.querySelectorAll('[data-acc]');
items.forEach((item) => {
const head = item.querySelector('.acc__head');
const panel = item.querySelector('.acc__panel');
if (!head || !panel) return; // null安全
head.addEventListener('click', () => {
const willOpen = !item.classList.contains('is-open');
// 他の項目を閉じる(1つだけ開くモード)
items.forEach((other) => {
other.classList.remove('is-open');
const oh = other.querySelector('.acc__head');
const op = other.querySelector('.acc__panel');
if (oh) oh.setAttribute('aria-expanded', 'false');
if (op) op.style.maxHeight = null;
});
if (willOpen) {
item.classList.add('is-open');
head.setAttribute('aria-expanded', 'true');
// 実際の高さを与えて滑らかに展開
panel.style.maxHeight = panel.scrollHeight + 'px';
}
});
});
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。