なめらかなアコーディオンの展開/折りたたみ
10年来Web開発者を悩ませてきた「height: 0 → auto」アニメーション問題を、View Transitions のスナップショットで解決。
詳細な説明
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-1、panel-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 ウィジェット全般。