【JS不要】CSSだけでdetails要素を開閉アニメーションさせる方法

従来、details要素のなめらかな開閉アニメーションは、JavaScriptなしでは難しいものでした。

しかし、::details-content擬似要素が主要ブラウザでサポートされたことで、CSSのみで実現できるようになりました。

数ヶ月かけて完成させたJS版のdetails開閉アニメーションはお蔵入りになりそうです…。

目次

::details-content擬似要素について

::details-content擬似要素は、details要素の展開・折りたたみ可能なコンテンツを表します。

<details>
  <summary>タイトル</summary>
  <p>コンテンツ</p>
  <p>コンテンツ</p>
</details>

例えば上記のようなHTMLの場合でも、divなどのラップ不要でコンテンツ全体にスタイルをあてることができます。

details::details-content {
  background-color: skyblue;
  padding: 0 1em;
  opacity: 0;
  transition: .3s;
}

details[open]::details-content {
  padding: 1em;
  opacity: 1;
}

実装例:

タイトル

コンテンツ

コンテンツ

::details-content擬似要素は、2026年現在、最新バージョンの主要ブラウザで広くサポートされており、サポート外の環境であっても、一部のアニメーションが発生しないだけなので、実用上は問題なく利用できます。

CSS Grid版(ブラウザ対応優先)

See the Pen Details Accordion (Grid) — CSS-only by hisa (@hisaaashi) on CodePen.

::details-content擬似要素をGridコンテナとして扱い、行の高さを0frから1frへと遷移させることで開閉アニメーションを実現しています。

CSS Gridの構造上、コンテンツをラップするdiv要素が一つ必要になりますが、制御のしやすさを考えれば十分に許容できるコストです。

<details>
  <summary>...</summary>
  <div>
    <p>コンテンツ</p>
  </div>
</details>
ポイント
  • コンテンツの親にdivが必要
  • 最新の主要ブラウザであれば使える
  • CSSの指定に少しコツがいる

レンダリングのイメージ

<details>
  <summary>Details</summary>

  <!-- ブラウザが生成するコンテナ(内部にslotを持つ) -->
  <::details-content> 
      
      <!-- slotに挿入される実コンテンツ -->
      <div>
        <p>...</p>
        <p>...</p>
      </div>

  </::details-content>
</details>

CSSは、以下のような具合に役割を分担することで、非対応環境でもレイアウトが崩れないフォールバックを兼ねた構成にできます。

  • ::details-content:制御に必要な最低限のスタイル
  • div:デザイン系のスタイル
/* 開閉アニメーションの制御 */
details::details-content {
  content-visibility: auto;
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--d);
}

details[open]::details-content {
  grid-template-rows: 1fr;
}

/* コンテンツ */
details > div {
  min-height: 0; /* 0frでの開閉とページ内検索を両立させるための指定 */
  padding: 0 1em;
  opacity: 0;
  transition: padding var(--d), opacity var(--d) ease-in;
}

details[open] > div {
  padding-block: 1em;
  opacity: 1;
}

Safariのバグ対策

本来であれば、::details-content擬似要素にtransition-behavior: allow-discreteを指定するのが定石だと思うのですが、Safariでは期待通りに動作しませんでした。

代替案としてcontent-visibility: autoを指定したところ、Safariでも安定してアニメーションを実現することができました。

/* Safariで動作しない */
details::details-content {
  transition-duration: .3s;
  transition-property: content-visibility;
  transition-behavior: allow-discrete;
}

/* 動作する */
details::details-content {
  content-visibility: auto;
}

おそらく、要素が「レンダリングの対象(レイアウト計算の対象)」としてより厳密に扱われるようになったため、レンダリング・タイミングのバグを回避できた可能性があります。

ページ内検索の漏れを回避

0froverflow: hiddenの組み合わせでコンテンツを閉じてしまうと、ページ内検索でヒットしない挙動を確認しています。(Mac環境)

details::details-content {
  /* 高さを0に */
  grid-template-rows: 0fr;
}

details > div {
  /* これがないと完全に閉じない */
  overflow: hidden;
}

試しにdiv要素に対しmin-height: 1pxで少し高さを確保してあげると、期待通りページ内検索にヒットするようになりました。

details > div {
  overflow: hidden;
  /* 以下を追加 */
  min-height: 1px;
  margin-top: -1px;
}

色々と検証を重ねた結果、min-height: 0でもページ内検索にヒットするようで、overflow: hiddenを指定せずとも折りたたみ状態を実現できることが確認できました。

details > div {
  min-height: 0; /* 0frでの開閉とページ内検索を両立させるための指定 */
}

結果として、CSS Gridで開閉を行う実装では、以下の2点が「安定した折りたたみ挙動の鍵」となりそうです。

  • grid-template-rows: 0fr(高さ制御)
  • min-height: 0(最小サイズ制約の解除)

interpolate-size版(将来の標準)

See the Pen Details Accordion (allow-keywords) — CSS-only by hisa (@hisaaashi) on CodePen.

もう一つのアプローチは、root要素にinterpolate-size: allow-keywordsを指定する方法で、これまで不可能だった「高さ0からautoへのアニメーション」が可能になります。

:root {
  interpolate-size: allow-keywords;
}

details::details-content {
  content-visibility: auto;
  height: 0;
  padding: 0 1em;
  opacity: 0;
  transition-duration: .3s;
  transition-property: height, padding, opacity;
}

details[open]::details-content {
  height: auto;
  padding-block: 1em;
  opacity: 1;
}

ただ、2026年5月現在はまだ Safari や Firefox が未対応、かつ今後のサポート時期も明示されていません。

とはいえ、非対応環境であってもheightに対するアニメーションが省略されるだけなので、「開閉さえできれば実用上の問題はない」と割り切れるのであれば、採用するのもありです。

ポイント
  • 最低限のHTMLで良い(div不要)
  • 使える環境が限られている
  • CSSが超シンプル

どちらが良いか

個人的には、現時点ではCSS Gridを使う方法がベストだと考えています。

実装コストは決して高くありませんし、比較的古いブラウザでもアニメーションが担保されるため、実務において安心して採用できるのが大きな強みです。

一方、interpolate-size は非常に魅力的ですが、サポート時期が不透明な現状では、普及したとしても実案件で気兼ねなく使えるようになるまでには、まだ時間がかかるでしょう。

いずれにせよ、JavaScriptを使わなくて済むのが本当に嬉しい。

カスタマイズに困ったらお気軽にご相談を!

  • 「ちょっとしたCSSの調整だけお願いしたい」
  • 「不具合を直してほしい」

料金は3,000円〜、お支払いは銀行振込・Amazonギフトカードなど柔軟に対応してます🤔

役に立ったら他の方にシェア

お気軽にコメントどうぞ

コメントする

目次