なめらかなアコーディオンの展開/折りたたみ

10年来Web開発者を悩ませてきた「height: 0 → auto」アニメーション問題を、View Transitions のスナップショットで解決。

UI Patterns

詳細な説明

auto-height アニメーション問題

height: 0 から height: auto へのアニメーションは、純粋な CSS では永遠に不可能でした。回避策(JavaScript で測定、max-height をアニメーション、grid-template-rows: 0fr → 1fr)はいずれも注意点があります。View Transitions API は両状態をスナップショットすることで問題を完全に回避します。

function toggle(panelId) {
  document.startViewTransition(() => {
    document.getElementById(panelId).hidden = !document.getElementById(panelId).hidden;
  });
}
.accordion-panel {
  view-transition-name: var(--panel-name);
}
::view-transition-old(.accordion-panel) {
  animation: 200ms ease-out both shrink;
}
::view-transition-new(.accordion-panel) {
  animation: 250ms ease-out both grow;
}
@keyframes shrink {
  to { opacity: 0; transform: scaleY(0.5); }
}
@keyframes grow {
  from { opacity: 0; transform: scaleY(0.5); }
}

兄弟要素もスムーズにシフト

キラー機能:パネルが展開すると、下の全兄弟パネルもルートクロスフェードグループ経由で新しい位置にアニメーション します。それを実現するコードは1行も書いていません。API がビューポート全体をキャプチャし、可視要素全てをアニメーションするからです。

view-transition-name でパネルを区別

2つのアコーディオンが同時に開いていて各々を独立にアニメーションしたい場合は、panel-faq-1panel-faq-2 のように一意の view-transition-name を付けます。一意の名前がないと全パネルがルートグループを共有して一緒にアニメーションします。

<details> 要素との組み合わせ

ネイティブの HTML <details> 要素と View Transitions は美しく協調します:

details.addEventListener('toggle', (e) => {
  document.startViewTransition(() => { /* 何もしない!toggle はすでに発生済み */ });
});

待って、これは動きません。toggle は DOM 変更の に発火するからです。<summary>click を使い、preventDefault() を呼んでタイミングを制御してください。

ユースケース

FAQ セクション、設定パネル、階層型ナビゲーションメニュー、ファイルツリービューア、DOM の高さを手動測定せずに高さ + 兄弟シフトのスムーズなアニメーションを得たい disclosure ウィジェット全般。

試してみるView Transitions API ジェネレーター

フルツールを開く