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 {
  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要素が一つ必要になりますが、スタイルの分離と制御のしやすさを考えれば十分に許容できるコストです。

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

レンダリングのイメージ

<details>
  <summary>Details</summary>

  <!-- ↓ これがブラウザによって自動生成される「外側の枠」 -->
  <::details-content> 
      
      <!-- ↓「内側の中身」 -->
      <div>
        <p>Default: Closed</p>
        <p>Initially collapsed...</p>
      </div>

  </::details-content>
</details>
  • ::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 {
  opacity: 0;
  padding: 0 1em;
  transition: opacity var(--d) ease-in, padding var(--d);
  /* ページ内検索対応 & overflow: hiddenの代用 */
  min-height: 0;
}

/* コンテンツ(オープン時) */
details[open] > div {
  opacity: 1;
  padding-block: 1em;
  margin-top: 0;
}

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;
}

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

ページ内検索の対応 & overflow: hiddenが省略可能に

details要素をGridアニメーションで実装させる際、0froverflow: hiddenの組み合わせでコンテンツを閉じてしまうと、ページ内検索でヒットしなくなります。(環境:Mac)

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

details > div {
  /* 本来gridでアニメーションさせる場合には必要 */
  overflow: hidden
}

試しにmin-height: 1pxで少し開けてあげると期待通り自動展開されました。

色々と検証を重ねた結果、overflow: hiddenの代わりにmin-height: 0を指定することで解決しました。

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

details > div {
  /* ページ内検索対応 & overflow: hiddenの代用 */
  min-height: 0;
}

今回のように、プロパティごとの役割の分離ができている場合は、このような指定が有効みたいです。

方法その②
interpolate-size: allow-keywords で実装

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;
  overflow: hidden;
  height: 0;
  transition-duration: .3s;
  transition-property: height;
}

details[open]::details-content {
  height: auto;
}

ただ、2026年5月現在はまだ Safari や Firefox が未対応なので、すべてのブラウザで同じように動く時期はもう少し先になりそうです。

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

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

どちらが良いか

個人的には、CSS Gridを使う方法が良いと思っています。

divが必要なものの実装コストは低めで、非対応環境でもpaddingやopactyのアニメーションは反映されるため、実務としても充分使えます。

interpolate-size: allow-keywordsはいつサポートされるかも不明ですし、サポートされてもすぐに実案件で使えるわけではないので…。

とにかくJavaScriptを使わなくて済むのが本当に嬉しい。

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

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

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

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

お気軽にコメントどうぞ

コメントする

目次