The current state of View Transitions is nice, but it could be even better …
~
The clip-path
problem
An 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.
As 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 better
But 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:
That’s much better, right?
To achieve this, there are 2 changes needed for View Transitions:
- A way to preserve the tree when building the View Transition pseudos.
- A new capture mode that captures certain properties (such as
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 better
At 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.
-
The new
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 thetext
’s pseudos be nested inside thebox
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 -
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
, andclip
properties.You can already try this out in Chrome Canary but note that the implementation still needs some work as the
border-radius
andclip
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: