beyond tellerrand 27–28 Apr 2026 Düsseldorf • Germany

Bramus Van Damme

Photo taken by

Bramus is a web developer from Belgium. He’s part of the Chrome Developer Relations team at Google, focusing on CSS, Web UI, and DevTools. From the moment he discovered view-source at the age of 14 (way back in 1997), he fell in love with the web and has been tinkering with it ever since.

Before joining Google, Bramus worked as a freelance developer in various frontend and backend roles. For seven years he also was a College Lecturer Web & Mobile, educating undergrad students all about HTML, CSS, and JavaScript – in that order.

Talk: Supercharge Web UX with View Transitions

Are you tired of disjointed web apps? View Transitions are the game-changer you’ve been waiting for. Whether your app is single or multi-page, this powerful API lets you create seamless, native-like experiences that captivate users.

Join Bramus Van Damme when he dives into the world of View Transitions, showing you how to replace jarring page loads with elegant transitions. Learn to harness the flexibility of CSS and the power of JavaScript to customise transitions and create a truly unique experience.

If you’re ready to take your web apps to the next level, this talk is a must-attend.

Transcription

Thanks, Marc.

( Applause )

All right.

Supercharged Web UX with view transitions. That’s the idea that I pitched to Marc. It was like, hey, Marc, can you come talk? He was like, oh, yeah, view transitions.

I’m going to do this talk. And this talk here basically is like the introduction to view transitions. And it goes through all the ins and the outs. But then I looked at the website because Tellerrand, I don’t know that word. I’m from Belgium. And I was like, okay, Tellerrand means to look a bit further, to look beyond the edge.(...) And then I was like, hold up. This talk here doesn’t make sense. I pitched the wrong talk to because this talk doesn’t look over the edge. So I’m going to switch things around. I will still be talking about view transitions, but we’re going to crank it up to 11 today because we’re going to go outside of the borders and do crazy stuff that maybe you shouldn’t do in production, but you could, but maybe you shouldn’t.

We’ll see. So view transitions, cranking it up to 11, or as the hotel likes to call it, view transitions are on fire.

Thank you, Brecht, for...

That was around 6 a.m. very early. I like to sleep in. Also, I think I saw this guy in the lab coach run away with a smoking oscilloscope.

(Applause)

So if you see him, grab him. I think he did it. Okay.(...) So as mentioned, I’m Bramus. I’m with Chrome DevRel. I’m also a member of the CSS working group. So I know a bit about CSS.(...) I’m also into scuba diving. I’m also into vinyl records, classic house music specifically.(...) So if you have any questions about these, come feel free to pull my sleeve. I’m still around here all day. So it doesn’t need to be about view transitions. It can be about CSS in general. I also run a blog. I’ve been running this one for 25 years this year.

And if you’re still doubting to start a blog, I would urge you to start one. Because this thing eventually landed me my job at Google. So start blogging, please. Share your knowledge.

All right.

Today I’m not here to talk about my blog or scuba diving or any of that. I’m here to talk about view transitions. This specification right here. And this specification basically gives you the power to allow you to do a transition between two different states of your website.(...) And two different states that can be something like this, right? Where on the left you have four items in the list. And then here on the right you have three items. So if you remove that purple box right there, maybe you want to animate that. Something like this maybe. Where it nicely moves out. Or if you add one,(...) that is a transition between two states. You went from four items to three and then from three to four there was a nice transition in between that. Or maybe something more advanced like this here. This is an overview page on the left and a detailed page on the right. And you can add a transition between that, right? You can do something like this where if you click the box, the box nicely grows and the title moves around. The visual moves around. And so on. Or look here. If I click it, the video even keeps playing. I think that is amazing. So that is a transition between two states. And I think this is great for UX. Because as a user, I get this. I clicked on that box and that box grew bigger. Like if you have an image grid somewhere, you click on the little thumbnail, the thumbnail grows into the big photo. You hit back, the big photo shrinks back into the thumbnail in the grid. I think this is great for UX.

So how do you do it? It’s fairly easy. There’s a lot of technology under the hood. But in general, it’s fairly easy. Step one is you identify a name, elements to transition. So you basically just take a look at your two designs and you start pointing at things and naming them. Like here, you have the box. And on the right, you also have the box. It’s a bit bigger, but that’s the box. And I’m not talking about the whole thing in general. I’m just talking about the black background. Because we’re going to do the Photoshop thing, right? We’re going to layer up our design into various layers. So we have our box. We also have a visual and we also have a visual there on the right. And we want this to transition from that state to that state.(...) We start naming more things, controls on both things. We have a title. We have an avatar. We have a button and so on and so on and so on. And also, interestingly, on the right there, we have a description that is not present on the old state. It is there on the detail page, but not on the overview one. And also, we have a back button and a top bar. Because we also want to animate them. So we also give them a name, even though they only appear in one of both states. And(...) with that done, with all those names done, we start adding them in our CSS by means of the view transition name. So our card in both the(...) overview and the detail, we give it the view transition name of box.(...) But it doesn’t need to be the same element. Because the title, for example, on my overview page, that was an H2. And in my detail page, that was an H1. That’s fine. You just give them the same name because then the browser will transition from the one element to the other.

So with all those names set and applied, you then trigger the view transition. And it can be same document or cross document.(...) Same document looks like this. It requires a bit of JavaScript. Browser support for this is great. What you basically do is that you take your method that updates the DOM, and you wrap it in document.startViewTransition. And that is like the trigger for the browser to then do the transition. So it will update the DOM under the hood, do a bunch of things, and then run a transition for you. Now, of course, this is perfect for progressive enhancement. So please add this as well. If your browser doesn’t speak view transitions, just update it without a transition, and you get the status quo right. You click the thing, and then it swaps over to the new state. That’s fine.

And there’s also another way because if you’re building an MPA, a multi-page application, also known as a website... Yeah.

( Applause )

You

triggered it by means of a navigation. So navigation can be you just clicking a link to the other page, but like a form submission is also navigation, because you submit the form to a new destination somewhere. Now, we won’t do the view transition stuff by default. You need to opt into this. And you do this using this little piece of CSS, add view transition, navigation, auto, and then the browser will do the view transitions for you. But it’s only on a same origin navigation. So it’s not cross origin because of safety reasons. Browser support, it’s in almost all browsers. Firefox is working on this thanks to Interrupt 2026.

But don’t let this prevent you from using it today, because if Firefox doesn’t interpret the rule right now, well, then you don’t get the view transitions, and when the day comes that it does, you do get the view transition. Hooray!

So that’s all our things that we have identified and named, but the browser does something magical with it, because what the browser will do is that it will create snapshots. It will create snapshots from the old state, and it will create snapshots for the new state. So let’s take a look at one in detail, for example, at the control zone,(...) because I think this one is interesting, because on the old state it only has three buttons, but on the new state it has five buttons. That’s not a problem for view transitions, because we take snapshots.(...) They are kind of like screenshots, but they are not, because the new one is live, the old one is a stale representation.(...) And with those snapshots, so the browser goes to the GPU layer, it grabs those textures from the GPU, and then we put them in a suga elements. We call the old one view transition old one, and we call the new one the new one, of course. And then in there you see the name again, because that was a name that we used to identify that thing.

And those pseudo’s, those get rendered inside a little pseudo tree, and that pseudo tree gets injected onto the transition root. We call the document that starts view transition, so you are running the view transition on the entire document. So we are going to inject this little overlay, this transition overlay onto the transition root, and then in there goes our little pseudo tree with a view transition group, image pair, alt and new.

The old one, well, that one will automatically fade out, so the browser will do fade out. And the new one, the browser will automatically fade in. And then there is also an image pair in there, so there is some blend mode isolations, because you do not want the pixels underneath to participate in that. And then finally you also have the group, and the group, that one is responsible for the positioning and the sizing. Because if you took a good look at our

snapshots of our controls, the old one was a bit smaller, and the new one was a bit wider.

See it right here, right? Also, the position has changed, because there on the left, if you measure it, the X and Y position from the top left of the viewport is different. So that group one there, that one is responsible for moving it, and while the group is moving, the old and the new one will fade in and fade out, you get a nice visual effect. Now, of course, I am simplifying this because we did not just capture the controls here. We captured a bunch more elements, so we have the card, the visual, the top bar, the avatar, and so on and so on. They are all in there, and those get rendered on top of your document.

Here is a 3D visualization, so you can see what is happening. If I am clicking there, and I have given every group a little nice golden yellow outline, so you can see what is happening with all those groups, then inside of those groups, all the new ones are fading in and fading out. Although here they are not all fading in and fading out, we have changed a bit, but if you take a look at the controls one right there,(...) come on, animation replay, if you take a look at the controls one right there, you will see it fade in and fade out, so you get a little cross-fade while the group is moving. This demo, by the way, is built by Maxi Ferreira. It is a great demo. It is like the post-trial demo of Vue Transition.(...) He really did a great job, so thank you, Maxi, for building that one.

All right, so we have identified and named everything. We(...) have started the Vue Transition by triggering. Step three is you can customize animations, but it is still the optional, because I have already told you, the browser will automatically move the group. For every group, it will create this unique(...) move the group animation where the name gets replaced by the name that you used as the Vue Transition name. You also have the fade in and the fade out that automatically gets applied to all of these snapshots, and that is part of the user-aided style sheets, which is a style sheet that ships with the browser. You get this one for free, but(...) if you look at it, this is CSS.(...) I know this. I know CSS. I know how to change this. I can just throw more CSS at it and customize everything, of course. Like here, for example, if I want to slow everything down, I just change animation duration to one second, and then everything will just move a bit slower, and the cross-fade will also move slower. You have already seen that one in the visualization demo where they built with the 3D there, right there. Those animations were running over duration of, I think, even two seconds. You can totally change that.

Other interesting things right here is if you take a look at the top bar, if you take a look at the top bar,(...) the top bar slides in and out. It does not need a cross-fade. Again, throw some CSS at it.

There is the top bar. You can see it is in this state, but not in that state. You can see this in the pseudo tree, because if you take a good look, there is only going to be an old snapshot or a new snapshot depending on if you are going from the overview to the detail or back.(...) As I already mentioned, throw some more CSS at it.(...) If there is only a new top bar, that is the only child within.(...) The image pair, slide it down. Otherwise, slide it up. That is how you can customize these animations.

Another thing right here that you see is video playing.

It gets you a bit. If you take a good look, the video here, the video of the person dancing, keeps playing as you are transitioning. It is not doing the cross-fade.

We have these two(...) snapshots, basically. We have a static screenshot of the old state, but we have the live representation of the new state. We do not want those to cross-fade, because then you get a stale frame that cross-fades to playing video underneath. That is a bit weird.

It is CSS. Here they are represented again. We have the old and the new one.

That one is live. Yeah. Old one. New one. We can again throw some CSS to it and say, “Hey, the old one, just display none of it. We never want to show you the screenshot that we had right there.” Then on the new one, we are not going to animate it. We are not going to fade it in. It is always visibly there when the view transition starts. That is how the video keeps playing in this. The TLDR view transitions is identified by name, trigger it, and then you customize it. Then in between somewhere, the browser pauses rendering, updates it down under the hood, and then takes the snapshots. But you do not have to worry about that, because it is all done automatically for you.

Some more examples where I am using this. For example, here I am changing the grid grab on a grid and the grid template columns.(...) You have nicely animated grids on the web.

CSS grid should have always worked like that.

But with a little bit of JavaScript document start view transition, we can update all the values there. Here is another one built by Adam Argyle, a former colleague of mine, where we are filtering through a list of items, and he also added some custom easing effects on it, like a little bounce and so on.(...) Or here, this one I really like by Dom Christie, where you can see the title right there. It is like moving up and moving down. There is a little stagger on there. I think this is like a really rich experience right on the web, all powered thanks to view transitions. So he did not really have to do anything to make this thing grow, the small photo into the big photo. View transitions does that all for you.

Or here is a more full experience built by Jake Archibald,(...) where you can have like these, you go from the detail to the overview and so on. I think this is also a really nice and rich experience that I get as a user.

So this is the poster child demo built by Maxi.

What a lot of people do not know is that Maxi built it after this design right here.

And if you take a good look, there is a second part to it.(...) As he scrolls up, the header shrinks, and I am like, “That is a transition between two states.”(...) There are two states right there, right? You have the big card and you have the big header and the small header, but that is a transition between two states. And it is not like a time control animation, it is like by scrolling(...) or by dragging the screen, but it is a transition between two states. So I was like, “Okay, how can I extend Maxi’s demo and add this to the code?”

So(...) before we do that, just something about the general CSS behind it is we just have a grid template(...) for the card, then when the card is small, we have a different grid template. That is the only change between those two states. I am just changing the grid template. So if we wrap that in document.startViewTransition, where we toggle the class list of the card, then we get the transition. To demonstrate you that it works, I have hooked it up to a button. So I am just like clicking and then the state changes. Then you get to see the default cross-fade between the old and the new state. That is because I have not identified anything on the screen yet. So I still need to do that.

And this is what happens if you do all that, right? So I toggle the button and then everything nicely moves up and down with everything.(...) Also, take a good look at here, this list of albums is also sliding up and sliding down. So we will also need to capture that. So identifying a name, everything. We again, we look at the thing. We just start pointing and naming, “Oh, I see the card over there. I see the visual over there. Oh, this one here should be visual because I need to have the same name.” So there is a mistake here on the slides.(...) We have the title over there. We have the back button over there. And then we have a bunch of crap there on the left as well that we-- like, we do want to fade them out, but we don’t want to move them as you are going to the next state. And also, as I already mentioned, we also need to capture the lists of tracks because those also slide up from the old state to the new state. So there is also like a transition happening for that one.

Then we trigger the animation. I’ve already shown you the code for that, which is this piece right here. We toggle the class and then we customize the animations.

I will show you the code, but first let me show you the animation through DevTools because you can totally use DevTools to debug all that. So if I hit-- if I show the animations panel in DevTools, we can pause all the animations. And if I then hit the toggle button, I can click on that one, and then I can scrub the timeline like this.

And then you can see the animation. You can also change the playback speed and so on. And by the way, this is not limited to view transitions. This works for any CSS animation or transition, so you can slow down time if you want to like really debug your animations. I think this is so cool. You can just slide through the list. And as you can see here, there’s like a little delay happening, right?

So if I start moving, the visual immediately moves, but the description, like the title here, it moves only a little bit later. So I’ve added an animation delay as part of my animation that I have used for all this.

Are you ready for the code?

I had to shrink it down a bit to get it fit on the screen. And I also had to place it across multiple screens because this is it. So we start off with our basic duration that I have set up. I’m building a mental timeline. I have built a mental timeline of one second, and then I have chunked it up. And I’m saying like, okay, the description should like only run for half of that entire duration with no delay, so the description should move immediately.

And then here the title, for example, which I mentioned, it should also move over 60% of the entire timeline, but it should be delayed by 20%. So I’m setting up everything right here, and then we’re going to throw mathematics at it to get it actually done.

We set the base duration on the view transition group. We make sure that the animation delay inherits. You no longer need this. We now placed it in the UA style sheet, but we used to do that back in the day. So here we’re saying everything runs over the duration of one second. All the groups and all the news and the old insight, duration of one second.(...) Then we still allow you to click through the view transition overlay, because by default it captures all the clicks. And you want to like click and drag, right? So you want your pointer events to still go to the document.

Basically, frame, set upside down, fade out, fade in.(...) We give everything the name that we mentioned, and then we start doing some nice things. Like for example, the cart itself, we want contents to be contained by it. So we want to clip its overflow, and we also like, we don’t really care with the animation. So we don’t want it to be like fade in, fade out, because it’s still the same cart, right? So we’re going to remove the animation from it.

The same thing with the title, the more meta, and the tracks. And here I did the trigger I already did. We’re going to hide the old one, and we’re going to immediately show the new one without it fading in.

And then here comes the mathematics part, right? Like for everything that we captured, we are going to set the animation duration. We’re going to take the base duration, which was one second, and then we’re going to multiply it by its duration, which was like the 60% or 20% and so on. We do the same for the delay, and then we also customize the animations because we want to slide it up, fade it out, and here slide it down and fade it in. And we repeat that for each and everything that we captured to finally end up at this part, the last piece of code, where we want to make sure that the tracks stay underneath the cart, because sometimes there used to be a small delay, you could see it creep up underneath. I think we fixed that bug, but it’s still there in my code. Because you never know, somebody might be using an older browser, right? Cool.

And just like that, we have gone through the code, and we have this. So you click it, and you toggle it. Nice.

And then if I...(...) Yeah. Those are things, right? Yeah, cool. So we have everything in place, but now I’m wondering,(...) how can I make this draggable? Because the animation don’t run on time. They run as I am dragging the page, so I want to run

the view transition by dragging on the page. Thankfully, this was already solved by Jake Archibald, who created this thing right here. That is a view transition between two pages, where he is dragging a button, and then he’s moving to the second... Well, it’s all about the link. And then he’s dragging to the next state, and then it’s sliding in and out.(...) So I took the code from Jake, right? I started looking, view source, it’s thing. “Hey, Jake, how did you solve this? View source.” He’s using the Pointer Events API for it, and he basically has three steps. So on pointer down, when you start clicking on the thing, he records which direction you want to drag to, you want to drag to the left or to the right. And then he also records the start and the start position. Then on pointer move, he’s constantly updating that position to calculate the delta. How far are you dragging from your original starting point? And then he updates all the animation, the current times of all the animations that are part of the view transition. I will show you the code. And then on pointer up finally, when you release it, he goes like, “Okay, you started dragging in that direction, then I’m going to continue playing the animation towards the end, and if you start dragging that direction, you’re going to continue playing towards the other part.”

He also used a bunch of other view transition tricks and features along with that, is that he doesn’t capture the root element, because everything that is captured becomes a snapshot, and pointer events are prevented on snapshots, because of security reasons. Like, for example, if you are morphing an image into a button,(...) and it’s like mid-fly cross-fading between the image and the button, and you then click it again, what did you click? Did you click the button or did you click the image? So that’s why we don’t allow clicks on the snapshots themselves, but we do allow clicks on the view transition overlay(...) if you opt into that by setting pointer events. So he also used that.

So the core of his code is that he’s starting a view transition, which is great, but he also needs to do something with the animations. But in order to do something with the animations, well, the animations have to be ready. So thankfully, every time that you create a view transition, you get back a view transition object, and there are some promises on there that you can’t wait. You can’t wait for the update callback to be done, which is when the new DOM is ready, so the JavaScript has changed the markup underneath. You can wait until the snapshots are ready, and you can wait until the transition has actually finished playing its animations. So he’s basically using this one right here.(...) When the transition is ready, so the pseudo tree has been constructed, the animations are there, but they are not playing yet. That’s the moment when he reaches in and he pauses all of those animations.

So here it is. I’m clicking and dragging. Cool. I’m clicking and dragging again. So that’s his joke-- Jake’s code applied to my page right there. So let’s take a look at some details. For example, this step right here, when you are starting the view transition, we need to pause all the animations. So we start the view transition, document.start view transition. Okay, cool. We store it in a variable, the active view transition. We wait until the snapshots are ready, so we know the pseudo tree is there, the animations are there, but they are not playing yet, and they will automatically start playing, but we’re going to be like, “Hold up, hold up.” We’re going to grab all the animations from the document element, and if the pseudo element link to the effect, this link to the animation starts with view transition, then we know we are grabbing one of the view transition animations. We’re going to grab all those, and then we’re going to pause them all. We’re going to say, “Hold up. From now on, I’m going to control time. Don’t play automatically using wall clock time.”

That’s that piece of code. The other one is here right there. As you are dragging, he’s then updating the current time of all of those animations. What you basically do is that we repeat our base duration here, and then we determine the drag distance, like where did you start your click, and how far are you along that one.(...) We are going to define, are you dragging up or down, or to the left and to the right, so we need to take the current X or the current Y, depending on which axis we are tracking. Jake was only tracking the X axis, but you can also track the Y axis, because that is what I needed. Then here, this is the key thing.

We’re converting pixel distance to time, basically. As you are dragging over the full distance, we are updating the current time between zero and one second, depending on how far you have dragged. Then we are updating all those animations with that current time.

Cool. This is the piece of code. It’s done, right?

Oh, not really. I’m(...) clicking and dragging, and the view transition run, but I still need to scroll with my mouse wheel, so I can click and drag to scroll down, but if I now scroll, it(...) doesn’t run.

I somehow need to combine, drag and scroll on a desktop, and that doesn’t make sense.

Also, this doesn’t actually work on a mobile device. I’ve tried it on an Android phone, and I’m tapping and dragging, and(...) it’s not doing anything. The reason there is that once you start tapping on your mobile device, that controls scroll, so we have a competition here going on, like, are you tapping to scroll, or are you tapping and dragging to run the view transition?(...) You can fix that by throwing some CSS at it. You were like, “Yeah, touch action, none.” It’s like, “Yeah, I’m controlling the dragging action right now,” but that has another side effect, because then you have actively disabled scroll on your touch device, so then you’re like, “Okay, maybe I should throw some more JavaScript at it to fix it.”

Net maps drag distance to scrolling. Yeah, you can do that, but then you’re losing a lot of things because momentum is crawling. If you fling your screen, the page goes, “Rrrr, then you want that to still happen,” but your JavaScript can’t cope with that. It’s like, “Hold up, hold up. Was this even a good idea to begin with?” I try this, and it’s not working. Also, why did Jake’s demo work? Because I tried Jake’s demo on the phone, and Jake’s demo works. He’s like, “Why doesn’t mine work?”

Turns out, yeah, so this is not a good approach, right? I tried something. I got stuck in the dead end. Also, if you’re wondering why did Jake’s demo work, he doesn’t combine drag and scroll. That’s why his one works, bears mine. I am vertically doing the drag. That’s also the scroll direction. By the way, if those two colors are the same right there, congrats, your color blind.

(...) (Laughter)

So, it turns out, instead of asking, “How can I make this draggable?” I have been asking the wrong question. Instead of asking, “How can I make this draggable?” I should have been asking myself, “How can I make this scroll-driven?”(...) I heard an “Ah, somebody very excited about scroll-driven animations.” So am I.(...) So am I. So, I’m going to show you the final code, but do note, this is a lot of sidesteps that I took. I had many dead ends, so I’m going to show you one of the solutions that I tried to come up with, so here it goes. And this is the one that listens to the scroll event. I also tried a bunch of other things right there.(...) This is basically the code. So if you are on scroll, we’re going to run a function. If you are within a certain scroll offset, well, then we’re going to start the view transition if there is none yet. If there is one, we’re going to update the animations. And then if we are outside of our scroll distance, then we are going to skip the transition, which means, like, “Hey, and the view transition, you just complete to the end.”

So we still have this class to toggle that we’re going to do. Yes, we’re still going to await the transition. Are you ready? We’re going to pause all the animations and so on. But also, interestingly, we need to reverse the animations because if we are dragging the page up, everything needs to shrink. But if you are dragging the page down, everything needs to grow and our durations need to be flipped, so we need to reverse our animations as well.

That’s the code. We also do some cleanup. I will show you later.(...) And then updating animations. Again, right here, we are tracking scroll progress. We are mapping that to time, and then we are updating the current time. This is the same code that I nicely borrowed from Jake. It’s the same code, except it also takes the reversal into account.

And then finally, some cleanup. When the transition is finished, so when it is ready, then we make sure that the right class is set on the card because you can start dragging up. But if you then change your mind, you start dragging down, you then need to reverse the clause at the end. So if you start dragging up, the card needs to be small. But if you then drag down again, the card needs to be large again, so you need to remove the small one from that. So that’s when the transition is ready, do some cleanup, and then we clear the active view transition. And here we have it. Ha-ha, I’m scrolling. Yay, it’s shrinking. The page is also scrolling.(...) A scroll driven view transition. Ooh, I’m happy.

So the main piece of code here(...) is this one, basically right. You start a view transition, you wait until it’s ready, you grab all the animations, and then you do something with the animations. And I’ve typed that piece of code a lot. In many demos that you can do with this, I will show you some more. And I’ve typed it that many times that I was like, hold up. I should just like remove all that crap and like put it in the function somewhere that I can reuse. I’ve done that, and I’ve not only put in the function that I can use, I’ve also put in the function that you can use because I’ve published an npm package that gives you that right there. It’s called the view transitions toolkit. It contains a bunch of utility functions that allow you to do like a bit of crazy things with view transitions, which is like perfect for beyond tolerant, I think.

And you don’t have to think about like all the code that I’ve shown you. That was just like one function that you can call.

So we have got animations in there, for example, right? And here I am debugging everything that you can see, like it gives you the key frames and which shooter it was applied on. You can also here right there, you can’t see it in the back. But like if you check the documentation, you can also filter like, I only want to have that animation from that specific pseudo. I only want to new one or I want to group one and so on.

Built upon that, I’ve also built something else where you can start and pause a view transition. And then you can like scrub the view transition as well, right? Those are also two functions that you can use. And then I’ve combined it all again in the scroll driven view transition using those functions. So all that code that I’ve just shown you, a lot of the code, not all of it, basically now goes on to this, right? You import the pause and scrub functions from a toolkit, and then you pause the view transition and then you scrub it as you are progressing your scroll. And that’s basically it.

So that piece of code, it’s amazing. And you can do a lot of things with it. Because one of the complaints that I hear about view transitions, they’re like, “Hey, the keyframes are not performing enough.”

You can roll your own as a solution. Because if you run the view transition and your page is subject to jank,(...) your animation stutters.

Here, let me show it again. You click and there’s jank, and(...) you don’t want it. And the culprit right there is the width and the height that is being used. Because if you open up DevTools, you will see this little red triangle there. It says, “Okay, this animation couldn’t be composited. It’s running on the main thread.” And right there, you will see at the bottom, like, “Okay, this is why. It’s because the height and the width can’t be run on the compositor.” Now, in Chrome, we recently landed a change to that. If the width and the height remain the same throughout the entire animation, we do allow the animation to run on the compositor. But if your width and height does change, well, it’s still running on the main thread. So the culprit right there, the width and the height.

You could say, “Okay, let’s just remove it, right?” Because, like, “Okay, Chrome has optimized this case, but other browsers haven’t.” So if we just, like, grab the keyframes and then delete the width and the height and then set it back again,(...) that doesn’t work because it’s only width and height. It only works if the width and height are the same. And also, the get keyframes function, we had a bug in Chrome up until version 137 where the end keyframe was wrong. It was totally wrong. There is a workaround I will show you.

So the solution to these non-performant keyframes are, let’s roll your own flip, right? It’s first, last, invert play, going by Poluis back in the day. So what you basically can do is you can extract all the data that you need from the keyframes and then transform it to... transform, yeah, to a transform or translate if you want.

And I have a solution that also works in older Chrome versions.

So we’re going to use the View Transition Toolkit again to extract the box animation right there, and then we’re going to grab the keyframes. Now, with those keyframes that we have right there, we’re going to extract the transform because the browser generated it for us. We’re going to cast it into a DOM matrix, and that way we can read a bunch of information from it, such as the left and the right, which is in the E and F properties of that one. So we do that one for the first keyframe, which is the old state. We do that one for the new keyframe, which is a new state, but it does need to work around for Chrome less than 137.

And then you build, with that data, you build your own translate scale, X and Y. So this is your from keyframe, and then this is your to keyframe, and(...) then you use those keyframes and you set it on the thing. And that way you have a-- let me first show you this light. And that way you have an animation that is not subject to check. It just keeps playing because it can run on the compositor.(...) The bug fix for Chrome, by the way, this is the bug fix. It’s basically time travel. You are traveling to time because the end keyframe is wrong. But if you grab the animation, you have pause it, and you set its current time to the end time, you have forwarded the playhead of the animation to the very end. So if you then do a get computed style, you have the actual value at the end of the animation. So then you can grab the info from it again, and then you rewind the time back to zero because you want the animation to start from zero. So that it starts playing.

If you are running like, okay, but why not just do get bound and client tracked? We can do that in JavaScript, right, and figure out where the thing is. The problem is VTransitions use a different containing block.(...) Get bound and client tracked is bound by the layout viewport. VTransitions use something called the snapshot containing block, and you can see the address bar is part of in there. So everything, if you do the get bound and client track, you would get back incorrect coordinates.

If you want to know more about this, I have a bunch of words about it on my blog. And yes, the slides will be shared afterwards so you can click all the links as well.

Also, you can forget all the code that I have just shown you because it is part of the new transition toolkit. Now it is just one(...) function that you call Optimize Group Animations, and it works. You cannot just apply it though to every element that you want to do because if the element has a different aspect ratio before and after, you can get distortions. So you need to verify and check if it works for you. If it does not, you need to split up things into a front layer and a back layer, and then do counter scale, complicated stuff, but I am sure you will figure it out.

And then here we have it, right? So the optimized and the not optimized side by side. Again, okay, cool.(...) Another thing that I hear, another piece of critique that I hear is that, okay, when you start a VTransition, it is document that starts VTransition, so you are locking up the entire document.(...) You can re-enable pointer events, which I have already shown you, or you can also use something magical, which is called element-scoped view transitions, and we recently shipped that in Chrome 147.

So instead of calling document.startVTransition, you can call some element.startVTransition, and it will run the view transition, but only on that element. So it will only look for view transition names inside of that little mini DOM tree.

So your DOM tree, this is a browser part, so your DOM tree does not look like this, but instead it gets injected onto that one element and you have everything in there, and the rest of your document remains interactive, which is great.(...) Here you can see it in action. I am reordering one list, but I’m also reordering another list, and you can do it simultaneously because you are two different sub-trees, and you can even nest view transitions with elements-coped view transitions. I think this is one of the additions that we were missing in view transitions that we really needed, but we now have it in Chrome 147, and hopefully other browser vendors will follow soon. If you want it, be vocal about it, state of CSS, reach out to your local browser vendor, let them know that you want it.

So yeah, concurrent and nested view transitions. Wow, I’m so badly needed this, and now we have it in Chrome.

A third piece of critique is that you are animating pixels instead of the elements, because we are taking snapshots, right? So we are capturing pixels from the graphics layer, and then we are blending them, fade in, fade out.(...) You can totally bypass this using a custom animation or rely on transitions. You can see the problem here. Look at the border radius.

It’s just cross-fading from the one border radius to the other. I don’t want that. I want the border radius to nicely grow and shrink.(...) Here is the fixed version.

I want this right. I want where the border radius nicely does its thing.(...) You can see the pixels here, still the text, because I’m capturing them separately, so you can see what is happening there. But the thing right here is the border radius. I want that one to nicely grow and shrink. The thing that you have to do for this is you have to split everything up into a foreground layer and a background layer, and then on the background layer, you can use a CSS transition.

So we have our card, which is the background layer, with different values when it’s small or big.

And then when we have that, we are going to add a transition to that. Transition all two seconds. Don’t use all, please, but I’m using it here for the sake of gravity. So please list out your properties that you do want to transition. And say, like, hey, whenever one of these changes, just transition them from the one value to the other. The browser will do that for you. And then here’s a thing that I’ve already shown you as well. I’m going to display none, the old snapshot. So we’re going to hide that one, and I’m going to immediately show the new snapshot. And that’s how you do it.

Here’s an article about it.(...) Shout-out, by the way, to Martin Trapp, who is a person who told me, like, hey, you need to use transitions, because before I was using animations, which was a bit too complicated, and Martin was like,(...) why don’t you just use transitions? I was like, of course. So thank you, Martin, for the tip that you have shared here.

I’m also working on something to have it in the View Transitions toolkit. It’s not there yet. It’s a work in progress. But hopefully you can just call this and be done with it as well.

A fourth critique, yes, is that interruptions, view transitions, skip to the end.

Because, like, here you can see it, right? If I click, it moves to a new position. But if I start rage-clicking, and we all do that, just admit it, the ongoing transition to its final destination skips to the end, and then the animation starts from the new end position to its new new position. It’s like, that’s not really what I want.(...) The problem there is there are complications with the snapshotting process. Like, if something is mid-flight, what should we then snapshot, because there is no element. Thankfully, you can get very hacky at this.

Because, like, if the box is moving from here to there, there’s like this line, it moves midway, and then if I click the page again, like, the new location is there at the bottom, I want it to move from that middle position towards the bottom right there, right? I think this is what I want to happen.

So I’ve tried that.(...) Here’s a solution. So you click, and it moves, and if I click and I click again, so I capture, like, the mid-flight position, and I start a new animation. But as you can see, it’s not that smooth. Like, it starts a new animation with the same duration, which is not what you want. Because, like, the problem is, like, if it’s not moving, like, this takes up 60%, almost 60% of the time, but then the second part takes up one second, and it should also be, like, 50%, I think. Or even ideally, you want it to, like, curve(...) through everything. Like, I think that would be a nice thing, right? Where you click and you click, and then it nicely moves. I want websites to be like that.

So I threw some JavaScript at it. That was like my go-to thing. So I recorded all the intermediary positions, again, done by the toolkit. Then I created SVG through all those dots, and then I update the animations, and I move it along a path, and that was very complicated. It does work. It is a bit glitchy, though. Like, it does work, and here you can see what’s happening, but it’s so complicated. You shouldn’t be doing that, because this is a much nicer one. Look at how smooth the dot is moving.(...) I think this is really cool.

And it doesn’t use SVG. What it does use, it’s a trick mentioned to me by Kevin Dotty, who I met at State of the Browser. We talked about this. He was like, “No, no, you should use relative animations.” And the concept is basically this. So as the box is moving from here to there, to the top right, it’s like mid-flight, and then if you click again, you want to start a new animation. What you basically do is that you capture the delta from the target position to the final target position, so you capture this extra vector, and then you stack it on top of the existing animation. So this animation right here, this first part, will run for like 600 milliseconds. The last part will run for 400, but then you stack a new animation that lost one second on top.(...) And then the box does something like this. And here’s a trick for it. The keyword here is “accumulate.” You create a new animation, and you accumulate it on top of the existing one. Instead, the default behavior is replacing “accumulate” is a one. Check out the pen for more details, and thank you, Kevin, for showing me the trick. And here you can see it in action. Like, here I’m shuffling items. I shuffle, shuffle, and then I start rage-clicking. You can see, like, okay, this is smooth. I want this on my pages. I’m also going to try and--it’s a work in progress. I have some code ready. I’m going to add it to the View Transition Toolkit as well, so that you can use it as well without needing to think about all these coordinates and stuff.

I’m going to skip critique five because we’re almost out of time, so we’re going to just go to number six.

Snapshovel elements bleed out of the container, and that is the thing. So here I have--these are the solutions, which I will mention to you. Like, here I have the list-re-shovel thing, but without the elements called View Transitions. And by default, all these snapshots bleed out of their container, and that is because snapshot elements, well, they render into the View Transition Studio layer, which sits on top of the entire document, including the top layer. So all the snapshots, they render on top of this container that was clipping the contents. Thankfully, you can fix this. You can use--like, here’s the fix. Cool. You can use nested View Transition groups where you go like, “Okay, I’m going to capture the UL as the View Transition Name Albums wrapper. We’re going to capture all the stuff inside of it.” But then on the UL, we’re going to say like, “Okay, all elements that you captured that are a child of me contain them within my own very snapshot.” And that’s how you have it. The View Transition Studio tree then looks like this. So we still have our View Transition group. There, you have a new one, View Transition group, Children, which contains all the children. And that one becomes a child of the View Transition group, and it’s a sibling to the image pair. So you have View Transition, View Transition group, Image pair, All, then New, still hierarchically. But then you also have a new one with the group. And then on that group, if you add overflow clip, content gets clipped. The cool thing is,(...) if you use elements called View Transitions, we all do this automagically for you. So you don’t need to do the contain thing and clip everything. We just do it for you. I think this is a good default.

And then, now on to the last two critiques, and then I’m going to let you go. Critique seven is that you can’t polyfill View Transitions.

You kind of can. Maybe you shouldn’t.

Like a Jurassic Park code, right?(...) The good thing is, View Transitions, well, that’s a specification. And a specification is basically a bunch of instructions for browser vendors that say, like, okay, if you do this, do that, do that, do that. Like, all these steps are listed out. So you can implement it in JavaScript or TypeScript, right? You can do that. So I did that. I used something to capture everything. But please do not use it in production. It’s not a polyfill because, like, I can’t suppress rendering. I can’t update the DOM while rendering is suppressed and so on.

But it was a nice experiment. And I wanted, like, okay. Here you can see it in action. And you can see the glitch, right? So this is View Transitions, all powered by just JavaScript, not the browser itself. It works, but you can see, like, it glitches. So please don’t use that. And then I wanted, like, okay, what if I(...) keep all the JavaScript stuff but remove the animation bits from it? And that is perfectly possible. So that’s the View Transitions mock, which you can import and install. And then this right here, like, the basic flow is you capture, you update resolvable, and so on. And then the View Transitions mock has everything in there, but all the visual stuff is removed from it. So that way, if you import the View Transitions mock and you register it, you can just call document.startViewTransition without doing the check for the progressive enhancement because the browser will-- well, I will provide it for you if the browser doesn’t speak View Transitions. And if the browser does, it will use the real View Transitions. The promises are on there and so on, so you can use it as if the browser natively supported it.(...) And the last one, this is the final script.

(Video Playback)

Cut. OK. Internet Explorer did it first.

Yes, that is right because Internet Explorer had something called Interpage Transitions.

And the description is like, just like Microsoft PowerPoints, you can have these nice transitions when the web change-- when the web page changes. And here are some effects. Like, this was recorded in IE6, so you have, like, a box in. And then you have a circle in.(...) Oh, pretty cool, right? And the way that it worked--

Internet Explorer. The way that it worked is that you had these meta tags, and then you did the reveal transition with a duration, and then you gave it a number. And then the number was like one of these. So you had 1 to 22. So you had 23 effects. And also, if you entered the number 23, you would get a random effect from it.(...) So you had it in PowerPoint, and you also had it on the web. So then I wanted like, OK, I could totally do something with it. So I wrote IE page transitions that adds it back to the browser, right? So you can have a box in effect. Woo! And then you can have strips left up. Yay! Like that. You can have everything. And the way that it works is that I take these existing meta tags that are already there. You add the cross-document navigation if you want to do the MPA thing. And then you just import my library, and that’s it. And from that moment on, those meta tags will start working. So browser port-- isn’t this a solid in Firefox? Because they don’t have multi-page view transitions. And of course,(...) Internet Explorer 5.5.8 also supports this.

So with that, I’m at the end. I think I’ve talked way too long. I’ve given you many building blocks to build something. You can build simple interactions, like maybe a counter going up or down. Or you can make these more rich experiences, where you’re going from and two things. I think this is a nice storytelling way of showing people what they can do. Or like here, for example, when you are filtering through a list of items, I think this is really nice. So please go out, try view transitions, build something crazy with it, build something creative with it, and together we can make the web a better place. Thanks.

(Applause)

Our wonderful partners

A massive thank you to our amazing partners, who without, beyond tellerrand would simply not be possible. Thank you!