本文へスキップ

アコーディオン

クリックで項目が開閉し、アイコンが回転。一度に1つだけ開く排他制御で高さを抑える。

プレビュー

クリック

操作クリック/タップで動きます。

使いどころ

FAQ・仕様一覧など「見出しは知りたいが本文は選んだものだけ読みたい」場面に向く。1項目ずつしか開かない排他制御なので、全体の見通しの良さ(縦に並ぶ見出しの一覧性)を保ったまま、開いたページの高さを最小限に抑えられるのが利点。逆に、複数項目を同時に見比べたい用途(比較表など)には排他制御が邪魔になるため、その場合はJSの「全て閉じてから開く」処理を外し、複数同時に開けるアコーディオンに作り替える必要がある。また、開閉のたびに直前まで読んでいた項目が閉じてスクロール位置がずれるため、極端に長い本文を持つ項目を混ぜると体験が悪化する。本文が長くなりがちな内容は、アコーディオンではなく別ページや別セクションに切り出す方がよい。

仕組み

高さのアニメーションを grid-template-rows: 0fr → 1fr の変化で実現しているのが要点。ac-body を1行のグリッドにし、行のサイズを0frと1frの間でトランジションさせることで、中の ac-content の実際の高さを都度JSで測らなくても、CSSだけで「0から本来の高さまで」の滑らかな開閉ができる。開閉の排他制御は、クリックされた項目が開いていたかを wasOpen で先に記録し、いったん全項目の is-open を外してから、閉じていた項目だけ改めて is-open を付け直すという単純な総入れ替えで実装している。アイコンは「+」の文字を45度回転させて「×」に見せているだけで、開閉自体はクラストグルのみで完結する。

実装の注意

grid-template-rows のトランジションによる高さアニメーションは、scrollHeight を測ってmax-heightを操作する旧来のJSテクニックより簡潔だが、比較的新しいCSSの挙動に依存しているため、対応が必要な古いブラウザを含むプロジェクトでは事前に動作確認しておく必要がある。もう一つ具体的な落とし穴として、.ac-content の padding-bottom は is-open クラスの有無だけで 0 と 12px を切り替えており、transition の対象に含まれていない。そのためgrid-template-rowsが滑らかに0fr⇄1frと変化する一方で、paddingはクリックした瞬間に数値だけ即座に変わり、開閉のごく初動でわずかにカクつく。気になる場合は padding もtransitionの対象に加えるか、paddingで余白を作るのをやめて ac-content 側に固定の下マージンを持たせる構成に変える。

アクセシビリティ

現在の実装は button 要素をヘッダーに使っているためTabでの到達とEnter/Spaceでの開閉というキーボード操作の基本は成立しているが、aria-expanded と aria-controls が付いていない。WAI-ARIA の Accordion(Disclosure の集合)パターンに沿わせるには、各 .ac-header に aria-expanded="true"/"false" を開閉と同期させ、対応する .ac-body に id を振って aria-controls で結びつける必要がある。これによりスクリーンリーダー利用者は「これは開閉できるボタンで、今開いているか閉じているか」を音声で把握できるようになる。排他的に1つしか開かない挙動自体はARIAの必須要件ではなく実装側の任意の設計だが、その場合でも「開くと他が閉じる」ことを事前に案内文などで示しておくと、支援技術での操作がより予測しやすくなる。

調整して使う

触る値は主に3つ。アイコンの表現(+回転/シェブロン回転/なし)、排他か複数同時開放か、そしてトランジションの時間(0.28s)。シェブロンに変える場合は「+を45度回してバツにする」回転角とは向きの計算が異なるので、アイコン素材ごとに回転角を作り直すこと。複数同時に開けるようにするには、クリック時に「全項目を閉じてから開く」処理をやめ、クリックされた項目自身の is-open だけをトグルする形に変えればよい。本文が長い項目とごく短い項目が混在する場合は、0.28sの固定時間だと長い項目だけ動きが遅く見えるため、実測の高さに応じて持続時間を可変にする(あるいは easing だけで速度感を揃える)と統一感が出る。

コード(コピーして使えます)

<ul class="accordion">
  <li class="ac-item">
    <button class="ac-header">
      配送について
      <span class="ac-icon">+</span>
    </button>
    <div class="ac-body">
      <div class="ac-content">全国翌日配送対応です。離島・一部地域は2〜3日かかる場合があります。</div>
    </div>
  </li>
  <li class="ac-item">
    <button class="ac-header">
      返品・交換ポリシー
      <span class="ac-icon">+</span>
    </button>
    <div class="ac-body">
      <div class="ac-content">お届けから14日以内であれば、未使用品に限り返品・交換を承ります。</div>
    </div>
  </li>
  <li class="ac-item">
    <button class="ac-header">
      お支払い方法
      <span class="ac-icon">+</span>
    </button>
    <div class="ac-body">
      <div class="ac-content">クレジットカード、コンビニ払い、銀行振込に対応しています。</div>
    </div>
  </li>
</ul>

タグ

同じカテゴリ「ナビ・リスト操作」のほかのパーツ

関連パーツ