Instead of duplicating an animation on the ::view-transition-group
pseudo, you can also rely on CSS transitions on the original element … if you’ve set it up correctly.
~
🌟 This post is about View Transitions. If you are not familiar with the basics of it, check out this 30-min talk of mine to get up to speed.
~
# The animation approach
In https://brm.us/view-transitions-border-radius I shared how you can nicely animate things like a border-radius
with View Transitions. To recap, View Transitions animate snapshots and because of that things like a changing border won’t nicely animate but they will fade from the old to the new snapshot.
To work around that I suggested to replicate the border animation and put it onto the ::view-transition-group
pseudo. For example, if the border-radius
of your #card
element changes from 0.25rem
to 3rem
, you’d create such an animation and apply it to the ::view-transition-group
as follows:
@keyframes adjust-group {
from {
border-radius: 0.25rem;
}
to {
border-radius: 3rem;
}
}
::view-transition-group(card) {
box-sizing: border-box;
border: 2px solid black;
animation-name: -ua-view-transition-group-anim-card, adjust-group;
}
:active-view-transition-type(shrink)::view-transition-group(card) {
animation-direction: normal, reverse;
}
::view-transition-image-pair(card) {
display: none;
}
Live demo (that animates more than only the border-radius
):
See the Pen
View Transitions with a Border Radius (2/3 – Workaround, with random text + border) by Bramus (@bramus)
on CodePen.
A key aspect to making this actually work, is that you have to individually capture the background part of the #card
and the content/foreground part of it. It’s only the background part that you animate.
#card {
view-transition-name: card;
}
#card > #card-content {
view-transition-name: card-content;
}
Check out the following visualization which, upon hovering, shows the two layers that get captured. It’s the background layer that gets animated:
See the Pen
Untitled by Bramus (@bramus)
on CodePen.
~
# A simpler approach
On BlueSky, Martin Trap – from “The Bag of Tricks for View Transitions” – let me know that there is a simpler approach.
When such things get too complicated for me, I usually drop the old image along with the new one’s entry animation and rely on the fact that the new image is a live representation of the original element.
That way, I can simply use CSS transitions on the original element during the #ViewTransitions morph and be done with it.
So instead of creating an animation on the ::view-transition-group
pseudo, Martin’s approach is to show only the new state of the box – through the ::view-transition-new
pseudo – and rely on CSS transitions to have it transition the border with a duration that is set to the same duration + timing-function as the View Transition. Nice!
In code, it becomes this:
#card {
view-transition-name: card;
transition: all 2s ease; /* Same duration and easing as the View Transition */
}
#card > #card-content {
view-transition-name: card-content;
}
::view-transition-group(card) {
animation-duration: 2s;
animation-timing-function: ease;
}
::view-transition-old(card) {
display: none;
}
::view-transition-new(card) {
animation: none;
width: 100%;
height: 100%;
}
Here’s the demo that Martin shared:
See the Pen
View Transitions with a Border Radius (original by Bramus) by Martin Trapp (@martrapp)
on CodePen.
This approach too requires you to decompose the element into a background (which you animate) and a foreground layer. What you can drop from the animation-based approach is the extra logic to determine the type
for the View Transition + the CSS to reverse the animation that goes along with it.
One (minor) nit with Martin’s code is that instead of transitioning all
, I’d transition only the properties that need to transition. The downside is that it can result in quite a big list, such as for this demo:
#card {
transition-property: border, background-color, border-radius, aspect-ratio, font-size; /* Yeah, that’s a lot of properties … */
transition-duration: 2s;
transition-timing-function: ease;
}
Thanks for sharing your ideas, Martin!
~
🔥 Like what you see? Want to stay in the loop? Here's how:
I can also be found on 𝕏 Twitter and 🐘 Mastodon but only post there sporadically.