Bento UIとはパネルが伸び縮みしながら配置が入れ替わるお弁当箱みたいなUI、View Transitions APIでCSSアニメーションが進化する
Post on:2023年7月26日
Bento UIとはパネルがお弁当箱のように配置されており、各パネルをクリックすると伸び縮みしながら配置が入れ替わるUIです。最近のWebサイトやスマホアプリでもよく見かけるようになりました。そんなBento UIをView Transitions APIを使用して実装されたデモを紹介します。
一昔前なら実装は面倒でしたが、Chrome 111から利用できるView Transitions APIにより簡単に実装できるようになりました。
Rediento -Bento Radio Group Carousel thing
実装にはChrome 111で実装されたView Transitions APIが使用されており、2つの状態間のアニメーションを作成しながら、1ステップでDOMを簡単に変更できます。
- 各パネルは、CSS Gridでレイアウト。
position
はなし。- ビジュアルのトランジションがアップグレード。
- 動きの軽快さを重視。
- 伸び縮みするスキッシュエフェクトをイージングで実装。
実際の動作は、下記デモページでご覧ください。
左上「Edit on Codepen」をクリックして別タブで開いた方が楽しめます。
※デモはChrome, Edgeでご覧ください。
See the Pen
Radiento - Bento Radio Group Carousel thing by Adam Argyle (@argyleink)
on CodePen.
実装を見てみましょう。
HTMLは各パネルをdiv
で実装しており、それぞれラジオボタンとラベルがあります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<fieldset id="radiento" class="bento"> <div> <input type="radio" id="huey" name="drone" value="huey" checked> <label for="huey">Huey</label> </div> <div> <input type="radio" id="dewey" name="drone" value="dewey"> <label for="dewey">Dewey</label> </div> <div> <input type="radio" id="louie" name="drone" value="louie"> <label for="louie">Louie</label> </div> </fieldset> |
View Transitions APIはJavaScriptで.startViewTransition()
を呼び出して使用します。
1 2 3 4 5 6 7 8 9 10 11 |
document.querySelectorAll('#radiento input').forEach(radio => { radio.onclick = e => { if (!document.startViewTransition) return; e.preventDefault(); document.startViewTransition(() => { e.target.checked = true; }); }; }); |
伸び縮みするスキッシュエフェクトは、Open PropsのCSSが使用されています。
参考: 一貫性のあるUIコンポーネントを簡単に実装できる -Open Props
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
@import "https://unpkg.com/open-props" layer(design.system); @import "https://unpkg.com/open-props/normalize.min.css" layer(demo.support); ::view-transition-group(*) { animation-timing-function: var(--ease-squish-1); animation-duration: .75s; } @layer demo { .bento { display: grid; grid-template-columns: 2fr 1fr; grid-template-rows: 1fr 1fr; gap: var(--size-3); min-inline-size: 50vh; aspect-ratio: var(--ratio-widescreen); & > :not(legend) { border-radius: var(--radius-3); background: var(--surface-2); @media (prefers-reduced-motion: no-preference) { &:nth-child(1) { view-transition-name: opt-1; & > label { view-transition-name: opt-1-label; } & > input { view-transition-name: opt-1-input; } } &:nth-child(2) { view-transition-name: opt-2; & > label { view-transition-name: opt-2-label; } & > input { view-transition-name: opt-2-input; } } &:nth-child(3) { view-transition-name: opt-3; & > label { view-transition-name: opt-3-label; } & > input { view-transition-name: opt-3-input; } } & :is(label, input) { width: fit-content; } } } & > div:has(input:checked) { grid-row: 1 / -1; grid-column: 1; } } } @layer demo.support { body { display: grid; place-content: center; padding: var(--size-5); gap: var(--size-5); } fieldset { border: none; > div { display: grid; grid: 1fr / 1fr; padding: var(--size-3); & > label { grid-area: 1 / 1; } } } } |
元ネタは下記ツイートより。
#CSS Radiento
a bento box radio group design with View Transition animations plus custom "squish" easing from Open Props 🤓
✅ grid layout
✅ no abs positions
✅ visual transition is an upgrade
✅ respects reduced motion
✅ keyboard still rockshttps://t.co/FsiVmkv360 pic.twitter.com/0halUZBQd5— Adam Argyle (@argyleink) July 17, 2023
sponsors