高さ auto の開閉アニメ
grid-template-rows を 0fr → 1fr にトランジションさせて、中身の高さを測らずに開閉する。JS は aria-expanded を切り替えるだけで、高さの計算をしない。
プレビュー
クリック
操作クリック/タップで動きます。
仕様書
- 向く場面
- FAQ・アコーディオンの高さ auto 開閉
- 中身の高さが可変で JS で測りたくない場面
- 複数同時に開けてよい補足情報
- 避ける場面
- 一度に1つだけ開かせたい設定画面
- 中身に横スクロール要素がある(overflow hidden で切れる)
- 構成要素
- 見出しボタン
- シェブロン
- パネル
- 本文
- 持っている状態
- 通常
- フォーカス
- キーボード
Tab で各見出しボタンへ、Enter/Space で開閉。複数同時に開ける
- 支援技術
h3 で包んだ button+aria-expanded+aria-controls、パネルは role=region(APG アコーディオンの契約)。reduced-motion では transition 無し
- 動き
開く 300ms ease-out(.16,1,.3,1)・閉じる 200ms ease-in。grid-rows 0fr→1fr で高さ auto を補間、閉じは片付けなので短く
デザインの要点
- height: auto はトランジションできないが、grid の 0fr → 1fr は補間できる。中身の高さを JS で測る必要がない
- 内側の要素に min-height: 0 と overflow: hidden が必須。無いと 0fr でも中身の最小高さで押し広げられて閉じない
- 開くときは 300ms ease-out、閉じるときは 200ms と短くする。閉じる動きは「片付け」なので待たせない
コード(コピーして使えます)
<div class="ex-wrap">
<div class="ex-item">
<h3 class="ex-h"><button class="ex-head" type="button" aria-expanded="false" aria-controls="exP1">
<span>料金はいつ請求されますか?</span><span class="ex-chev" aria-hidden="true"></span>
</button></h3>
<div class="ex-panel" id="exP1" role="region"><div class="ex-inner">毎月1日に前月分をまとめて請求します。初月は日割りで、無料期間中は請求が発生しません。</div></div>
</div>
<div class="ex-item">
<h3 class="ex-h"><button class="ex-head" type="button" aria-expanded="false" aria-controls="exP2">
<span>途中でプランを変更できますか?</span><span class="ex-chev" aria-hidden="true"></span>
</button></h3>
<div class="ex-panel" id="exP2" role="region"><div class="ex-inner">いつでも変更できます。上位プランへは即時、下位プランへは次の請求日から適用されます。</div></div>
</div>
<div class="ex-item">
<h3 class="ex-h"><button class="ex-head" type="button" aria-expanded="false" aria-controls="exP3">
<span>解約したらデータはどうなりますか?</span><span class="ex-chev" aria-hidden="true"></span>
</button></h3>
<div class="ex-panel" id="exP3" role="region"><div class="ex-inner">解約後 30 日間はデータを保持し、いつでも書き出せます。30 日を過ぎると完全に削除され、復元できません。</div></div>
</div>
</div>