The current state of View Transitions is nice, but it could be even better …
~
The clip-path problemAn area where View Transitions fall short is how it handles clip-path, border-radius, opacity, …
Take this demo, which has a view-transition-name on the grey circle and a view-transition-name on the text contained within that circle.
https://www.bram.us/wordpress/wp-content/uploads/2024/09/view-transitions-capture-mode-before.mp4As you can see in the recording, the snapshots cross-fade whereas you’d most likely want the clip-path of the circle to actually animate instead.
Also, the nested text bleeds out of its container; this because the snapshots are a flat list instead of a nested tree:
::view-transition├─ ::view-transition-group(card)| └─ ::view-transition-image-pair(card)| ├─ ::view-transition-old(card)| └─ ::view-transition-new(card)└─ ::view-transition-group(text) └─ ::view-transition-image-pair(text) ├─ ::view-transition-old(text) └─ ::view-transition-new(text)
While this outcome of these View Transition limitations could be acceptable in some cases, here it is not.
~
It can be betterBut what if this issues could be solved? So that you’d get the following instead:
– The clip-path on the circle actually transitions
– The text stays clipped by the circle
Like so:
https://www.bram.us/wordpress/wp-content/uploads/2024/09/view-transitions-capture-mode-after.mp4That’s much better, right?
To achieve this, there are 2 changes needed for View Transitions:
clip-path, border-radius, opacity, …) individually and copies them onto the ::view-transition-group().Combine the two, and you are able to get what you see in that second recording there 🙂
~
It will be betterAt the time of writing, Chrome is actively working on implementing these two new features, gated behind a feature flag. To try these out, you need Chrome Canary with Experimental Web Platform Features turned on.
view-transition-group property – part of the View Transitions L2 specification – allows you to determine where to place the snapshot. In the demo shown before, I have the text’s pseudos be nested inside the box group pseudo, like so:.card {view-transition-name: card;}.card a {view-transition-name: text;view-transition-group: card; /* 👈 Make the pseudo-tree for this “text” snapshot to be nested inside the “card” pseudo-tree */}
::view-transition└─ ::view-transition-group(card) ├─ ::view-transition-image-pair(card) | ├─ ::view-transition-old(card) | └─ ::view-transition-new(card) └─ ::view-transition-group(text) └─ ::view-transition-image-pair(text) ├─ ::view-transition-old(text) └─ ::view-transition-new(text)
You can also use a value of nearest to make it less explicit
2. As for the capturing, Chrome is experimenting with a new capture mode that animates a select set of properties directly onto the ::view-transition-group().
The set of properties we are looking at are clip-path, border-radius, opacity, mask, filter, and clip properties.
You can already try this out in Chrome Canary but note that the implementation still needs some work as the border-radius and clip properties aren’t implemented yet.
If all goes well, this new mode will eventually replace the old mode.
Pretty sweet, right?
~
🔥 Like what you see? Want to stay in the loop? Here's how: