Cranking View Transitions up to 11
Introducing Brahmos Van Damme and the View Transitions Topic
Bruce humorously introduces Brahmos Van Damme from Belgium with a series of anagrams before handing over to the speaker. Brahmos introduces himself as a Chrome DevRel team member focused on CSS and interactions, shares his background in electronic music and scuba diving, and strongly encourages attendees to start a blog — crediting his own 20-year-old blog with directly landing him his job at Google.
What View Transitions Are and Step 1: Identifying and Naming Elements
Brahmos introduces the view transitions specification, summarising it as enabling rich visual transitions between two states or pages of a website, illustrated with a list item animation and a full-page card transition demo built by Maxi Ferreira. He then introduces the first of three steps: identifying all elements you want to animate by comparing both design states and assigning them a matching `view-transition-name` in CSS, noting you can even morph between completely different element types such as an h2 and an h1.
Step 2: Triggering View Transitions in SPAs and MPAs
Brahmos explains the two ways to trigger a view transition: wrapping a DOM-mutating JavaScript method in `document.startViewTransition()` for single-page applications, and adding `@view-transition { navigation: auto }` in CSS on both pages for multi-page applications including standard websites with links and form submissions. He notes that cross-document transitions are restricted to same-origin navigations for security reasons, that same-document browser support is universal, and that cross-document support in Firefox is forthcoming through the Interop initiative.
Browser Internals: Snapshots, the Pseudo Element Tree, and Auto-Generated Animations
Brahmos explains what the browser does after a view transition is triggered: it captures snapshots of all named elements from both the old and new states, pauses rendering, then builds a pseudo element tree consisting of `::view-transition`, `::view-transition-group`, `::view-transition-image-pair`, `::view-transition-old`, and `::view-transition-new`. He walks through the auto-generated CSS keyframes that handle position, size, and crossfade for each group, and uses a 3D outline visualisation in his demo to show how all the individual pseudo element layers move during a transition.
Step 3: Customizing Animations and Community Demo Showcase
Brahmos introduces the optional third step — customizing animations — showing how standard CSS properties like `animation-duration` and custom keyframes override the browser defaults. He demonstrates practical techniques including directional sliding for the top navigation bar using the `:only-child` selector, and hiding the old snapshot to let a live video continue playing without an unwanted crossfade. He closes the foundational section with a showcase of community demos: a CSS grid gap animation, an Isotope.js recreation with a wobbly timing function, a staggered-title lightbox by Dom Christie, and a multi-page site demo by Jake Archibald.
Cranking It Up: Scroll-Driven Card Demo Concept and DevTools Inspection
Brahmos shifts to advanced territory, first noting the importance of respecting `prefers-reduced-motion`, then drawing inspiration from a Dribbble mockup to frame a scroll-driven card expansion as a view transition between two CSS Grid states. He walks through identifying and naming all the participating elements, triggers the transition with a button for initial testing, and then demonstrates Chrome DevTools' animations panel — showing how to pause, scrub, and slow down the transition timeline to inspect individual element animations and their staggered start and end points.
CSS Code Walkthrough for the Card Expansion Animation
Brahmos walks through the full CSS powering the card expansion demo, explaining how he builds a mental timing timeline to coordinate staggered animation delays and durations for each named element. He covers setting a one-second base duration, re-enabling pointer events so the page stays scrollable during a transition, handling aspect ratio differences between card states, applying the hide-the-old-snapshot trick for elements that remain visually identical, and inverting timing calculations to correctly handle both the expand and collapse directions.
JavaScript Implementation of Scroll-Controlled View Transitions
Brahmos explains how he made the card demo scroll-driven using JavaScript, highlighting the key technique of awaiting `activeViewTransition.ready` to access the fully prepared pseudo element tree. He then shows how to sniff out only the view-transition-linked animations by filtering `document.getAnimations()`, a pattern he borrowed from a Jake Archibald demo. A scroll event listener starts the view transition, immediately pauses all its animations, and then scrubs them by mapping scroll progress to a current time value in milliseconds, giving the user frame-perfect control over the transition.
Compositing Performance: Optimising Animations with the FLIP Technique
Brahmos addresses the performance problem of view transition animations running on the main thread by default, showing how Chrome DevTools performance traces reveal non-compositable animations flagged with a red triangle. He explains that `width` and `height` in the browser-generated keyframes prevent compositing, then demonstrates the FLIP (First, Last, Invert, Play) technique as a fix: reading element positions and sizes from the generated keyframes, then replacing them with `transform`-based animations that run on the compositor. He also covers a time-travel workaround using `getComputedStyle` to handle a Chrome bug before version 137 where keyframe values were reported as `none`.
Smooth Interrupted Transitions Using Relative Additive Animations
Brahmos tackles the jarring effect of interrupted view transitions, where clicking mid-flight causes the animation to skip to its end before starting a new one from a fixed position. He credits Kevin Daugherty with the solution: instead of calculating a new diagonal path, use `composite: accumulate` to stack a fresh animation representing only the remaining directional movement on top of the existing one. The result is smooth continuous motion even with rapid repeated interactions, demonstrated in a live shuffle demo recorded in Firefox to avoid a current Chrome glitch.
View Transitions Toolkit and Element-Scoped View Transitions in Chrome 147
Brahmos introduces the View Transitions Toolkit, a published package he built to abstract the recurring patterns from his explorations, including utility functions for `getAnimations`, `pause`, `play`, `scrub`, keyframe optimisation, and auto-navigation-type detection based on a JavaScript route map. He also introduces element-scoped view transitions, available in Chrome 147, which inject the pseudo tree onto a specific element rather than the document root, enabling concurrent and nested view transitions on a single page — a feature Brahmos calls out as something he wanted for a long time.
Polyfilling View Transitions and Reviving IE Page Transitions
Brahmos first describes his JavaScript polyfill for the view transitions API, acknowledging it cannot fully replicate browser behaviours like pausing rendering, but notes a lighter mock that polyfills only the API surface — removing the need for browser-support checks in application code. He then humorously revisits Internet Explorer's interpage transitions feature, which predated modern view transitions with PowerPoint-style wipe and box effects controlled by meta tags, and reveals a library he built to revive those effects on modern sites by combining the original IE meta tag format with the `@view-transition` CSS rule.
Audience Q&A: Code Attribution, Image Loading, and the CSS element() Function
Bruce hosts a short Q&A. Jake Archibald jokingly challenges whether Brahmos writes any of his own code given the extensive borrowing, and Brahmos explains he inherited both view transitions and the demos from Jake at Google. An audience member asks about image loading during cross-document transitions, and Brahmos describes the current render-blocking limitations and recommends prerendering via speculation rules as a workaround. A final question asks whether the live-projection capability of view transitions could enable the CSS `element()` function, which Brahmos enthusiastically endorses and urges the audience to advocate for via the State of CSS survey.
Our next speaker is from somewhere called Belgium. Yeah. So I asked him if he was gonna do the talk in Dutch or English, but he told me that apparently in The Netherlands, people don't speak proper Dutch. So he was going to do it in English. His name is Brahmus Van Damme, which is an anagram of madman bum raves.
And if you ever heard him speak before, you'll know just how appropriate that is. He's going to be banging on at you about some CSS malarkey called view transitions. An anagram of Brahmos of Brahmos of view transitions is naive bratwurst missions, which I think you'll find is completely accurate.
But nevertheless, give it up for Brahmos van Damme, the naive bum raves.
Thanks, Bruce. I didn't know that. Afternoon. Hi. View transitions cranking up to 11 safely maybe because, yes, I'm gonna show you some things that maybe you could use in production, but maybe you shouldn't. Or I'll I'll let you decide on that.
So hi. My name is Veremis. I'm with the Chrome DevRel team. I'm mostly doing CSS related stuff, interaction y bits, like scrolling animations or the intersection of both. If you have questions about CSS, come ask me afterwards, or come find me and my colleagues right over there in the top right top left corner from here where we have a booth.
And we can talk about a lot of things or point you to to the right people. I'm also up for chatting about electronic music, final records, scuba diving. So that's also possible. It doesn't have to be something tacky. The thing I wanna point out here, though, on this side is I have a blog, and I've had a blog.
Well, it's it's going to celebrate its 20 birthday or anniversary later this year. And I would recommend you yes. Thank you. And I would recommend you all to start a blog if you haven't done so. If you are doubting about it, please start a blog because I can draw a direct line from me having my blog to me landing my job at Google.
It does pay off. So share your thoughts. Share your ideas. We're very, very eager to hear your thoughts. Now I'm I'm not to talk about the history of my blog and so on and so on. I'm here to talk about this thing today, which is the view transition specification. You can read it from top to bottom. Or if you want a one line summary, here it is.
The view transitions specification allows you to create these rich visual transitions between two views of your web page or your website. Now two views or two states. Like, for example, this thing right here, where I have a state where I have four items in the list, and then here I have three items in that list.
And as I remove the purple one, maybe you wanna animate that, have a nice visual transition, like so. I hit the remove icon and whoop, it goes away. And if I add one, it falls in and the rest nicely scoot over. I think this is pretty nice. A more complicated example is this thing right here, where we have two actual pages on our website.
We have the overview page on this side. Yeah. We have the detailed page on there. And instead of you just clicking that black box there and then the layout changing and there you have the detailed page, Or maybe you want to have a nice transition where if you click the box, it nicely grows. The top navigation bar moves away.
You hit back, and so on and so on. As a user, I get this. I click the thing, and the thing then grows and moves around. And I think this is great for UX. This is a pattern that we typically see on native applications. Well, you can also do it on web because, yes, this is a website. It was recorded in Chrome.
So yeah, I think this is really cool. Demo, by the way, built by Maxi Ferreira. Wonderful guy, wonderful demo. Thank you, Maxi, for building that one. I really like this demo. So how do you do it? How do you do it? Well, it's fairly easy. All it requires is three steps. Now of course, as everything with CSS, it's easy.
And then it becomes a bit difficult. And then it becomes like a disaster if you try to do it if you don't really understand it. But my hope is here today to help you explain what and how you can do it. And then hopefully, it should be more easy to do. The first step is you need to identify and name everything that you wanna animate as part of the transition.
And that is very simple. You just have to look at your two designs, and then you start pointing at things and giving them a name. And you try to look for similarities between the two layouts. So for example, here on the overview page, I recognize the box. And then on the other side, I also recognize the box.
Now I'm not talking about the full card. I'm only talking about the black background box with the border radius on it because we're going to do the Photoshop thing here. We're going to layer everything up in several layers, and all the things that we want to capture are stuff that needs to move from the one view to the other and back.
So I recognize the box on both sides. It's the same box, so we want to morph that box into that box. The same thing with the visual that I have there. I have this photo of this person right there. I also have it on the other side. And then it needs to move to the other side, grow a bit bigger, and so on.
So we keep on identifying and naming all the parts that we see on our two designs, our two layouts. Now what is interesting here is on the detail page, I also have a description that is not there on the overview page. But I do wanna capture it because I want to fade that one in and move that in as part of that view transition.
The same thing with the back button. It also needs to animate as the view transition, as you are transitioning from that page to that page. And also finally, the top bar, we also want to capture that one. Because as I go from the overview page to the detail page, the top bar needs to slide out. If I go from the detail page back to the overview page, the top bar needs to slide in.
So that is the identify and naming part. Now we've only done it on paper here, like on our screen. Of course, we need to do it in CSS. And in CSS, we have a property for that, which is the view transition name property. And then you select your element or elements in both your states, and you give them the same view transition name so that the one from the one state morphs into the other one at the other state. So in both views, the card, well, that's the same selector. But on the overview page, for example, the title was an h two. And on the detail page, the title was an h one. And that is perfectly possible with view transitions, because we're going to capture a few things, which I'll explain later.
So yes, you can totally morph a title into a photo and then a photo into a button and a button into a paragraph. If you want to do that, view transitions has got you covered. That was step one. Step two is you need to trigger the view transition. And for that, you have two options. You have view transitions, same document view transitions, or cross document view transitions. And the same document one is when your document remains the same. So you're basically building application.
The document remains the same, and you are using JavaScript to mutate that DOM. So to add view transitions to that, you take your method that manipulates the DOM. So this one changes it. It doesn't show playlist. It mutates the DOM, but you wrap it in document dot start view transition. And that is the trigger for the browser to do things, to say, Okay, you want to do a view transition from the current state that you have on the screen to this new updated markup that you want to show.
Now, of course, you had a fallback for browsers that don't support it or for older browsers out there. Because browser support currently, it's available in all browsers. Hooray. Nice. But maybe people are running an older version of Chrome. Or maybe people are running a different browser that doesn't do view transitions yet. So there you want to provide the fallback where it says, hey, if you don't speak view transitions, just update the DOM and then be done with it.
Second way to do it, because this was the same document view transitions for single page applications, the second way to do it is when you are building a multi page application, where you're going from one document to another. And a multi page application, also known as a website. Yes. Turns out the web is pretty good at it.
You have a document, and then you put a link on there to another document. The web has been doing that for quite a long time. So navigation, that can be a link, which I already told you. But it can also be a form submitting to another page, because you are also submitting data to that other page. So that's also a navigation.
Now we won't do the view transitions by default there. There is an opt in that you need to do, and that is in CSS. So you add the add view transition rule there. Navigation set to auto. You add it on both pages. And then you will have opted in to doing a view transition between those two documents.
Another asterisk with this is that we won't do it for cross site navigations or cross origin navigations even. They need to be same origin. So I can do view transitions on my own site from one page to the other. But I can't do a view transition from my site to somebody else's website because that would have security implications.
So we don't want to do that. Browser support looks like this. It's currently work in progress in Firefox. And that is thanks to the interop effort. So later this year, we will see cross document view transitions also being available in Firefox. Honestly, I don't really care about this browser support table here because I think view transitions are a real nice progressive enhancement.
If your browser doesn't do view transition, well, you get the status quo right. You click the link and then the content changes, and it just changes. But if you do have view transitions in your browser, well, cool. Then you get a nice and rich visual transition between the two documents. So these here are all the things that we have identified and named. We have the trigger, which was step two.
Something interesting happens here. When you do that trigger, so that is either the navigation for MPAs or websites or the same document one using JavaScript, the browser does something. Namely, from the old view, it will take snapshots of everything that you gave a view transition name. It will then pause rendering. Behind the scenes, it will produce the new frame or the very first frame of the next state.
And then it will capture snapshots from that state as well. So you end up with a bunch of snapshots from the old state and a bunch of snapshots from the new state. Here's an example. Here are the controls. And I already find this very interesting as an example because, yes, the controls are different between the two. Here we have three buttons in the controls, and there we have five. Well, that's not a problem because the browser takes snapshots, and then it will render those snapshots into pseudo elements.
And those pseudo elements being the view transition old, of course, for the one in the old state, and the view transition new for the one in the new state. Now the browser won't just render these in your DOM somewhere. It will use a pseudo tree for that. And that markup looks a bit like well, it looks a bit it looks exactly like this.
And this piece of markup, this pseudo tree gets injected onto the element on which you called your view transition, which is by default, if you do document dot start view transition, the document. If you do the cross document navigation one, then it is also the document or the root element. So this view transition pseudo three gets injected onto the HTML element here or the colon root, as we can also select it.
And we call this element, we call that one the view transition root. Then we have the view transition overlay. Because yes, each and every one of these here has a meaning and a value. The view transition, that one is just an overlay which renders on top of your document. And it even renders on top of the top layer, by the way. So that's like the toppiest layer that we have in a browser where you can render stuff in.
We recognize the old one. That one will fade out. We recognize the new one. That one will fade in. So it's going to do a crossfade by default. Then we have an image pair in there, which is for blend mode isolations because we only want to cross fade those two layers without pixels underneath participating in that cross face.
So we need blend mode isolation. And then finally, have the view transition group, which is responsible for the position and size. You might be like, position and size? But, yeah, if we take a look at our two designs, the x and y position in both states is different. So it needs to move from that position to that position.
And the size also changes. So isolated in the view, this is basically what happens. If I click on the card, then this controls one, it will move around. And then it will do the cross fade from the old snapshot to the new snapshot. So that is happening by default. Now those animations, they are generated by the browser.
So this is user agent generated CSS. And it does this all for you. So you don't have to do anything right now except just calling document start view transition or doing the navigation. We recognize the group one in there. So the view transition group with controls, that one is getting a specific animation to move that controls onto its new position and size, along with new width and height.
Recognize the old one to fade out, and recognize the new one to fade in. And then the asterisk that is used there is to say all the pseudos that you have captured, old, old, pseudos and all the new pseudos, you get to fade in and fade out. If you're curious about the keyframes that were generated, again, this is taken care of by the browser for you.
So this is what the browser generates for you. To move the controls, it uses an implicit end keyframe. So there's no 100% keyframe in there or two keyframe. The styles are written onto that pseudo temporarily while the view transition is running. And then the front key frame says, hey, this is your starting position. And if you can't read matrices, no worries.
If it says one zero zero one at the start, then the first value after that is a translate x. And the second one is a translate y value. So where are you x and y on the screen? And you can see that it will move from those coordinates to those coordinates. And then the width and the height also change.
So again, this is generated by the browser. You don't need to do anything for this. It all works magically. So this is our pseudo tree. Of course, this is only part of the pseudo tree that I'm showing here because we captured more than just the controls. We had the title. We had the card. We had the visual.
We had the top bar and so on, so on, so on. So our c zero three looks something like this, where we have this little mini group, with the group, the image pair, the old and the new for the cards, but also for the visual, the top bar, the avatar, and so on. And each and every group in there will have key frames generated so that it moves across the screen, and then the old and the new ones will automatically fade in and fade out as the group is moving. If you wanna visualize this, because I'm more of a visual person, no worries.
I added a three d option to show you that in the demo. So you click it on. And here I've had outlines to all of the groups. So you can see what is happening to the groups. Like you can see here, top bar with the playlist, it's moving down. And then if you go back, you go into a detail, it's moving up. Take a look here at the visual at that box. If you hit back, the visual moves down.
So that has visualized what is happening with that pseudo tree. So step one, identify a name. Step two, trigger the view transition. And then step three is the next one, which is to customize the animations. But this is totally optional because I've already shown you the browser does a lot of the heavy lifting for you. It generates all these movements on the groups, it fades in and then it fades out.
Now in this demo that I've shown you, there are customizations that have been used. And looking at the code, this is the same code that I've already shown you. If I look at that, I'm like, holy crap. Like, I noticed that this is CSS. Right? So I can just take my own CSS and throw it at it, and that is exactly what you can do.
For example, for a demo, I have done this. I said, hey. You know what? All the groups, you have an animation duration of two seconds. And thanks to some more CSS in the UA style sheet, that duration is inherited onto the image pair and onto the old and the new. All the animations as part of the view transition will last for two seconds.
Another part where this is used is, for example, with the top bar. When you're going from the overview page to the detail page, the top bar, you want to move that away. You want to slide it out. But if you're going back from the detail page back to the overview page, well, the top bar needs to slide down.
I guess here's a demo. Click on the card. Top bar slides up. Hit back. Top bar slides down again. Looking at the pseudo tree, there is something interesting happening here. Because if you take a look at all the groups and then the old and the news, if you look at the one for the top bar, you will notice that there is only either an old one, an old snapshot, or either a new one, depending on whether you're going from overview to detail or from detail to back.
And then to select this one, like when there is only an old one so you can and I put only an old one or only a new one. Well, to select that one, we have CSS. We have the only child selector in CSS. Right? So we can customize it like this. Instead of having the default fade in and fade out animation, we're like, no. No. No.
No. When there's only a new top bar so we are going from detail back to overview, you want to slide it down. And if there's only an old snapshot in that pseudo tree, then you want to slide it up. So this is how you can customize it. Another interesting bit here is the visual. This is the card with the lady, and then you click on it, and then you go to the other page.
If you take a good look at it, there is something really interesting happening here, namely the video keeps playing as the view transition is happening. That's like, oh, holy crap. That's that's pretty cool. Right? And the way that it works is basically when the snapshots are taken, this is what happens. The old snapshot, that one is like a screenshot, actually.
It's like a stale copy of whatever was there. But then the new snapshot, well, that is a live view. It's like a projection of the original element in your DOM, but it gets projected into that new pseudo. So by default, if we use the fade in and fade out animations, we would end up with this where we have the old one sitting on top, the new one underneath.
And if we then do the cross fade, you will have this cross fade from a stale key frame to a video that is playing, and it looks weird. Pay close attention. It's like, Like, I don't want this. I I just wanna see the video. I wanna see the new pseudo. Well, you you can do that. Because you can say, like, oh, I don't care about this one.
I don't care about the old one. I just wanna hide it, and I only wanna see that new one. So the new one shouldn't do the fade in by default. Well again, a bit of CSS. You throw it at it. You say, hey, the old visual, display none. I don't want to see you. The new visual, no animation.
So no fade in. So it will just always be there without doing an animation. And if you then take your two snapshots with the one hidden and the one visual, lay them on top of each other and you play the transition, now the transition is playing. But there's no crossfade happening, so it's all smooth and very nice.
So the TLDR for view transitions is basically this. You have three steps. Identify a name. You then trigger the view transition. And then the browser does a bunch of stuff. It captures all the snapshots. It sets up the pseudo tree then. It prepares all those animations. And then you can customize those animations. And then finally, the browser will play those animations.
And that is your view transition. Some examples. Here is one where I'm toggling the grid gap on a CSS grid, but it's wrapped in document start v transition. So instead of just saying, hey. Your new gap is now two AMs or, like, half an m, I wrap that in document dot start v transition, and then the browser will do this.
Kind of wish that grid worked like this out of the box. I think this is this is nice. But yeah, document dot start view transition wrap wrap it in there. Another demo built by built by Adam. Are where are you, Adam? Built by Adam, which is a recreation of Isotope JS. And what I really like about this demo is that you can also see the bouncy, wobbly effect going on there.
That is done by changing the animation timing function, and then using the linear function to create this little wobble effect. Again, whenever one of the controls change, you wrap that in document. StartViewTransition. And then in JavaScript, you do that DOM mutation. And it will do all the capturing for you as long as you give each and every one there a view transition name.
Another demo built by Dom Christie, where there's this typical lightbox one. You click on the small photo, then it grows into the big one. Now what I really like is this attention to detail right here, where the titles have this nice staggered effect as they are entering, and then they stagger in the reverse as they are exiting.
Really nice demo. I like this one. And finally, a demo built by Jake back in the day, which is a more real website here where you have an overview page and detail. You might recognize some faces there. But you filter it, then it changes. And then what I really like as well is that if you are on a detail and then you click the title back, like the HTTP to a Cree title, it nicely slides back as the button is fading out.
Really, really cool. So yeah, view transitions. Now I've only shared a part of what is there to say about view transition. But I want to move on to cranking it up to 11 to do more crazy stuff that you can do with view transitions. One thing that I do want to call out though here is respect user preferences.
So if the user has prefers to reduce motion set to reduced, then don't run the view transitions or change your animation so that they are more subtle. Like you don't want to move stuff around, but maybe just have the default crossfade. There's a bunch of things that you can do with view transitions. If you do want to know all about this, go check out my talk that I gave at, what was it, JSB, I think, React Brussels a while ago.
That talk goes into detail. Or if you're more a fan of reading, well, good news. We have a lot of documentation up on our website, developer.chrome.com, where you can review everything. It has sections on same document view transitions and also cross document view transitions. All of the info is there. Now what a lot of people don't know is that Maxi Ferreira, he built he built his demo after this dribble mock up.
And if I look at it, there's something interesting happening here. You click the card, and as you scroll, it also animates. And when I see that, I'm like, that's a view transition between two states. Like, yes, there are two states. Well, state one being that one and state two being that one, and then there's a view transitioning happening.
Now it's it's not by clicking a button running by time. It's like by you scrolling through the thing, but that is a view transition between the two states. And the two states, well, there's not a lot of difference between the two states because you can totally, build this with with CSS Grid, and then your grid template areas would look something like this.
And then the small version is just a changed value for grid template, where instead of showing the meta and the title and description and the image and so on and so on, you are just showing the image and title and the more meta and all the rest you don't care about. So that is the only change between those two states.
Now if you want to do a view transition with that, well, I've already told you. Right? You do document dot start view transition. You take your method that updates the DOM. You wrap it in document dot start view transition. Here, I attach it to a button just like to test things out. I go for it. I click on it.
And, oh, it's only doing a cross fade between the whole document. But that is because in the UA style sheet, so that's a style sheet that comes with the browser, It has stuff like the page background is white and the font is Times New Roman 16 pixels by default. Stuff like that goes in there. Well, one of the rules that if the browser supports view transitions, one of the rules in that user agent style sheet is this one. It says, hey, the root element, you get a view transition name of root, which is by default, we're going to capture a snapshot for you if you're doing view transitions so that you have a crossfade. Now we don't want to have that crossfade.
We want to have this. And I've attached it to a button, but, like, this is what we wanna see happen. Right? You want the yeah. Boom. You wanna see the big card move into the small card, and then some some crossfading is is happening. But to do that, we have to do the whole dance again. Right? We have to identify and name everything, trigger the view transition, which we've already done, and then customize the animation.
So step one, identify and name your elements of transition. Again, we get to look at designs, and we get to point and name things. Woo hoo. I see the card over there. Yay. I see a visual over there. Yay. I see a title over there. The more meta block. I see a back button as well. More meta. And then I see a lot of crap on that design that I don't care about, but I do want to animate it. So again, add a view transition name to it so that it becomes part of that view transition.
And to be clear, because there is some confusion about this, when you are doing a view transition from that page to that page, it results in multiple elements being animated, but it's one single view transition. So it's not all those individual elements doing a view transition. No. It's one single view transition that consists of multiple parts moving around. So identify and name all that stuff, but we also need to identify and name something else, namely the tracks list.
Because we don't want that tracks list to just cross fade to that other state. No. We also want to move it so that it moves to the right position. Those are all the names. We do that in CSS. I will show you the code later on. We trigger the view transition. I've already shown you that one. This is a call to document dot start view transition, where we basically just toggle the class.
That's it. And then we customize animations, which is optional. And I will show you a lot of code here to do that. But before I show you the code, I wanna show you what I actually built by using DevTools. Because in DevTools, you can show a animations panel. And then in that panel, you can say, hey. You know what? Whenever you have animations running, pause them.
I don't want them to run. So if I click the button, all the animations are created, but they aren't running because DevTool is preventing that. And if you then click on the card there for that animation that was captured, you'll see all the animations here, and you get this little timeline. If you come from the flash days from back in the day, this will be pretty familiar.
And then once you have that in this state you can also hit this, by the way, like 10%, 25%. You just slow down time. So the animations will run, but just a bit slower. But once you have this thing here, well, you can grab that red line there, which is the play head, and you can scrub the timeline. Is it scrubbing?
Yeah, it is scrubbing. So now I'm controlling time by scrubbing that little playhead right there. And there's a few interesting things happening here in the animation, like for example, the title there. The title, it doesn't animate over the entire duration of the full animation. So the full animation is like the title. It starts a bit later in the animation.
And also, its time is not the full time for it. You can have it visualized here. Like, there's a bunch of dots there where an animation starts and stops and so on. So DevTools, I really like this feature. It's it's nice. Firefox DevTools has it well, by the way. So, yeah, let's take a look at some code.
Right? It's not gonna be x 86 code, so it should be readable for most of you. It is CSS. And here it goes. Oh, yeah. Had to shrink it down and spread it on multiple sides, but here it goes. So basically here, what I do is I set up the parts of the animations. So the title that I mentioned, which is right over here, it should only last for 60%, and it should be delayed 20% into that animation.
So I'm adding some numbers here where I'm building up this mental timeline that I will then use later on in calculations for animation duration and animation delay. So those are all those numbers. The next thing I do here is we set up the base duration. Like you want the entire view transition to last for one second. And then also we want to inherit the animation delay onto those other pseudos. So I told you that the animation duration by default is inherited from the group onto the image pair onto the old and to the new.
That is also true for the animation delay, but not in all versions of Chrome. We only added that one later to the spec. So Chrome caught up later on. So you need that for all the Chrome. Firefox and Safari had it out of the box when they shipped their view transitions implementation. The next thing you want do is you want to disable pointer events on your view transition overlay.
Because as I mentioned, the view transition overlay renders on top of the document, on top of the top layer even. But it also captures all pointer events by default. Now we don't want that because we want to scroll the page while the view transition is running. So we re enable that using just one line of CSS and declaration. They are pointer events.
Then we have a bunch of key frames, side up, side down, and so on. We give all the elements a view transition name. Hooray. Then we deal with differences in aspect ratio between the card because it has some differences. Jake has an article about it on his blog. Go check it out. Then finally, we do the trick like we did with the video.
Like, for some elements, we just wanna show the new snapshot and not the old one. We don't care about it cross fading because they are the same, so we do that here as well. And then we start setting those times. Right? When the when there's only a view transition old for a description, so when we are going from the big card to the small card, we want that animation to start a bit later, and we want that animation duration to be a bit shorter than the rest. And also in the other direction, we do the same thing, but we need to reverse the numbers.
So here we do one minus, and then we also do the base duration minus and so on. We do that for a bunch of other elements and so on and so on. And then finally, we also set the z index minus one on the tracks because we want the tracks to stay underneath the card. There used to be a moment in time when Chrome shipped and it was like a bit jittery and and the list would creep on top of the card, we fixed that, but we still leave it in for the older browsers.
There's no harm for keeping it in right there. And that is the code. And with that, here is the demo. I am scrolling. Oh, I'm clicking the page, of course. And now it's working. So this is how I've I've already shown you this part right here. So with that in place, then comes the next question. Right? We chopped up the problem in several subparts because the next question is, how can I make this scroll driven?
Because now it's just a button, but I wanna scroll as I go. To cut the long story short, there's a bunch of interesting late nights with a lot of versions and a lot of rides that happened. There's some of them that I wanna highlight, but I'm only gonna go into detail of one. Like, one approach that I tried is where I used pointer events to move things forward.
If you were at Beyond Telegram and you saw my talk there, I talked about that one in detail. You You know you that it went nowhere, so I'm not going to bother you with it. And there's also one where I actually built scroll driven animations using the JavaScript variety of the natively built in scroll driven animations. And you end up with a scroll timeline, and I copy that scroll timeline onto the view transition pseudo animations.
Totally works. But Firefox doesn't do scroll driven animations yet, although they will this year, thanks to Interrupt twenty twenty six. Hooray. So I finally resorted to just using scroll event listeners to set up my code. Now what all these versions have in common is this commit right here. And that commit contains this piece of code.
And yes, right now we're gonna move from CSS day to more JavaScript day because I'm gonna show you a lot of JavaScript code from now on. That piece of code right there, this is like the key to unlocking everything. So the first one here is await active view transition dot ready, which is a promise that you can await.
So the thing that I haven't told you yet is when you start a view transition, you get back a view transition object. And on that object, there are a few promises that you can await. You can, hey, wait for the DOM update to be ready. Wait for the pseudo elements to have been created and the animations to be ready. They're not playing yet, but they're about to play.
And also wait for the view transition to be totally finished, maybe to do some cleanup there. So we're gonna await that transition dot ready one so that we have the pseudo tree in place with all of the animations, because then comes the next step of the code where we're gonna sniff out all the view transition animations. There is an easier way to do this nowadays.
In spec, I filed a CSS working group issue for that one. We got a resolution, but no browser supports it yet. So we still need to use this piece of code. What you're basically doing is you're saying, oh, go back. Go back. Oh, yeah. Maybe one detail to note here is that this piece of code, I totally stole it from Jake from this demo, where he had a gesture driven view transition where you drag a button from the left to the right, and it's controlling a view transition.
So thanks, Jake, for the code. I owe you a beer for that one. So back to the code. So what you basically do is we get all the animations on the document. So that's all animations, even including non view transition related animations. So we wanna filter that set of animations. You wanna say, hey. I only care about the animations that are linked to the document because we did document start view transition.
I don't care about the footer having an animation or some spinner spinning. Like, I only want the animations linked to the document. And finally, I only want those animations that are linked to a pseudo whose name starts with view transition. And that way, you end up with a bunch of animation instances that are only linked to the view transition.
So that's the core of the piece of code. Now I want to talk I want to skip to that part right here, the one that listens to the scroll event, because there I'm actively going to use that piece of code. So let's look into detail. I'm adding a scroll listener. Let's checks the scroll position. If you are within a certain scroll range, because you only want the view transition to run when you are at the top of the document and scrolling the first bit of the document, if you are within that range, we are starting the view transition if there is none running, but we immediately pause all of the animations.
If there is a view transition running, well then we scrub through that list of animations. And finally, if we are outside of the range, we skip a transition so that it does its cleanup state. The start view transition and pause the animation's code looks like this. We start a view transition. We store it in a variable, the piece of code that I stole from Jake right there.
And then once we have all of the animations, we pause them. And we say like, hold up, hold up. You're no longer running on clock time. I'm going to control time now. Then we also do a reversal, of course, because if you are scrolling from the small card to the big card, then the animations need to play in reverse.
So we also take that one into account based on the selector. Then updating the animations is also fine. It's also pretty easy once you understand it. You take the scroll progress. So how far have you scrolled? And you get a percentage from that. So it goes from zero to one here, basically. So it's a number. And then on the next slide, we convert that scroll progress to time. So we multiply that scroll progress percentage by the total time so that we end up with something between zero and one thousand milliseconds. And then we apply that to the animations.
Or if they are playing in reverse, we need to do some small inversion. And that's something that I skipped over. You might have noticed in the AKS start view transition and pause the animation. There's also a little bit of cleanup there at the bottom, which looks like this, which says, hey, if the animation is finished, so the animation the view transition has finished, then we want to make sure that the card has this right class.
Because if you have the big card and I start scrolling that way, I add the small class. But during that view transition, if I then change the scroll direction, I want to end up with a big card again. So here I am ensuring that we have the right class at the end of that view transition running. And then we set it to null.
And here is the result. Here is me scrolling through the page and then having the view transition run. Holy crap. I have to speed up. So yeah, this piece of code, it came in really, really handy. I've been using it for other cases as well because you might get some feedback from your colleagues and say, hey, the key frames for view transitions aren't performing enough.
And they're not wrong. If you have something and then your main thread gets blocked, and it's like you will see it right here. The main thread is blocked, and then your animation is janky. And that is because the view transition animations by default, well, they run on the main thread. You can use DevTools for that. So if you do a performance trace, then you see the red triangle there at the top right.
I added that to DevTools. You see the red triangle there. It says, hey, this animation can be composited. And then if you click on the thing, then right here you will see why it can't run on the compositor. How width and height can't be animated on the compositor. And yeah, that's actually true. If you take a look at the key frames, the computer ones, you will see height and width there.
And it's a bit stupid because the height and the width don't change here. Well, in Chrome, we have optimized this. If the width and the height don't change, then we don't force the animation to run the main thread. We let it pass onto the compositer. And maybe some other property can kick it onto the main thread. But of course, if your width and height values change, well, yeah, then we don't have an optimization in place.
You can try and delete the width and height from the key frames and then write them back. Yes, that would work. But again, only works if the width and the height stays the same. And also, had a bug in Chrome before Chrome one thirty seven where the key frames were turned to wrong format. So you couldn't really rely on that one.
So you need to do something else. Right? To solve this, well, the solution is there. We're on your old flip. First, last, invert play, coined by Paul Lewis back in the day. And here's the code for that. You start the view transition. You sniff out the one animation that is tied to the box, and then you get its key frames.
And here are the key frames. And then you start reading values from that one. So from the first key frame, which is the front key frame at 0%, you read out the transform. You cast it into a DOM matrix. And then you get the e and the f. So that's the fifth and the sixth value from that to do the left and the top.
And then you can also just get the width and the height from those key frames. You do the same for the second key frame, the after key frame, so the final destination. And that way, you have the before and the after rectangle of where the box was and where the box will end up at. And then you can use those values to do this, a translate and a scale as a from key frame.
And then you do that again as a to key frame. And these properties, well, the transform property can perfectly be animated on the compositor. So here you now have performed key frames. You can see it in action right here. So I'm clicking and I'm blocking the main thread. You see the one on the right. Yay, it keeps running.
And it also works with different sized boxes in the old and the new states. So that's perfectly fine. If you haven't been paying close attention, there was this mention about Chrome 137 that didn't work. Well, the problem there was if you read the key frames, holy crap. The width and the height said none, and the transform was also none. It's like, that's not right.
So how can you work your way out of that? Well, time travel. Time travel is a solution to a lot of problems. And what you basically do is this right here. So if it's a buggy Chromium by detecting if the value is none for the matrix, you set the animation. You take the animation and you set it to its last position.
At that point, you do getComputedStyle, which gives you the matrix from that transform. And then you use that as a rect author. And then of course, you rewind back time so that the animation starts at the start again. So yeah, out of time. Great movie. If you are wondering, by the way, why don't you just do getBoundingClientRect? We have APIs for that.
All the problem is they use different origins to position everything. So if you do a getBoundingClientRect, that uses the layout. Port. So that one is used by DOM layout. But in view transitions, you use something called the snapshot containing block, which is a bit different because there's this top bar right there at the top, including your address bar.
Safari doesn't do it for some weird reason. I don't know why. So yeah, the address bar right there. So you can't use a get binding client. You want to know more about this, I have two articles about it on how you can create more performant animations with view transitions and dealing with the snapshot containing block. So yeah, that piece of code, really, really interesting, awaiting the free transition to be ready, sniffing out of the animations.
Here's another scenario where it helped me, because interrupted view transitions skip to the end. Like if you start a view transition, it runs from to another position. But then if you start rage clicking and admit it, you all rage click on a website sometimes, you will see that the animation skips skips forward to the end, and then it does a new transition. So this is what's happening.
You wanna move the box to the top right, for example. It starts moving. Then midway, you click again to start a new view transition. Well, the box, it will just skip to the end, and it will start a new view transition from that point. And you don't want that. You want to animate from this mid flight position to the bottom right. So you want to calculate that and start a new transition.
Well, you can do that using the code that I've shown you. But then you end up with a problem where this thing ran for about 60% of the entire land. So that's zero point five nine seconds. And then you start a new animation that lasts one second. There's like a little disconnect if you it's quite jarring. And you can see it here in this demo.
Like, if I click, then I click again, I click again. You'll see, like, it's it's a bit like it's not smooth. So instead of this, like, maybe you wanna, like, calculate that somehow, something like that. You can totally do that. You can grab all the intermediate positions. You can sort those in variables, and then you create an SVG between all those variables.
And then you animate along the path, and then you get something like this where you click and then it dynamically computes a new path. And yes, it's glitchy as hell because Chrome has a glitchy bug there. But you don't wanna check that code. It's the reason why the code pen is still private. And also, there's a reason why I have a gazillion tabs.
Like, I have many varieties of that one. Yeah. Don't don't don't check that one. Thankfully, I met Kevin Daugherty at State of the Browser in 2025. Think he was like, no. No. You need to use additive animations, but not only additive animations. You need to use relative additive animations. So his thing is, like, if you are moving from that position to that position, it goes mid flight, and then you click.
It should end up over there. He's like, don't calculate the diagonal. No. No. No. Calculate the extra animation from the new start position to the new end position, but staggered on top of the existing one. So the remainder that you end up with is this animation in a downwards direction and that animation in that direction. If you then play that one, woo, it goes really, really smooth.
Trevor Guy. I implemented that right here. You can see this is smoother. Right? I recorded this in Firefox because we have a glitch in Chrome. I'm nagging engineering about it. Don't worry. Don't worry. Don't worry. So this is the code if you do want to check it out. The key thing here is composite accumulate at the end so that you stack it on top.
And here's another demo where it's being used. Shuffle, shuffle. And I click shuffle, shuffle, shuffle, shuffle. And it nicely stacks all of the animations on top. So yeah, I did this piece of code. Really helpful. It helped me in a lot of cases. And I was so fed up with typing it over and over again and copying it from code pen to code.
And I was like, hold up. This can be easier. So I abstracted the way in a function, and I've totally shipped the package for you to also import it from. The result is the view transitions toolkit. Can find on chrome. Dev slash view transitions toolkit. And it contains a bunch of utility functions. So for example, here, getting all of the animations.
It's showing the debug here. That is now just to call get animations. Another one to scrub through an animation. Well, now we have pause, play, and scrub functions that you can just pass your view transition object into, and you have control over that one. Another one, the scroll driven animations. I rewrote the demo using that code. So the code now just looks like this, where you import pause and scrub. And then you call pause and scrub.
And that's it. Another one, optimizing the keyframes. That's now just one call. Just optimize group keyframes, and that's it. And then, like here, optimize it. You optionally pass in an identifier there. And then also, one that I really like is autonavigation types, where depending on the page you are coming from or the page you are going to, I'm running a different type of animation.
And this is the code that I use for it. I set up a route map in JavaScript. And then based on that, it will automatically apply types that I can use in my CSS. So if the active view transition type is from index combined with to about, I want to slide from the left and slide from the right. But if it's from the in from a detail to an index or from the index to a detail, I want to morph a specific image.
Now this here relies a bit on JavaScript. We are looking into a way to giving you a CSS only version of that. If you are interested about that tomorrow, during the lunch break, 01:20, I think, is the time, we will have a session there in the Red Cafe. Noam and I will be talking about that. So, yeah, view transitions toolkit.
Check it out. There's more stuff I want to talk about. There's there's two more things that I want to mention to you before I go. One complaint is the document is not interactive while the view transition runs. Yes. And that is totally true because we have the view transition overlay sitting on top of things. Yes, you can re enable pointer events, but you can also use something called element scoped view transitions, which is amazing.
So instead of calling document dot start view transition, well, you can just call any element dot start view transition. And the result is a pseudo triad gets injected only onto that element itself. It's available in Chrome one forty seven right now, not in other browsers. Speak to your local browser vendor representative sitting here on the first row to let them know that you want it, because I think this is a great addition.
This was one of the things that I really used for view transitions. The sudo tree then looks something like this. So instead of injecting it on root, it is injected on the list that you call document dot start view transition on. And here is the result. You have a view transition on just that list, which means you can run two view transitions at the same time.
And you can even nest view transitions. So while this is moving, I'm also moving the list individually. I wanted this so hard, and now we have it in Chrome one forty seven. So yeah, concurrent and nested view transitions. And find out more here on this page, scoped transitions. We have an article on developer.chrome.com.
I'm going to skip this part right here because scoped view transitions uses this under the hood. It's called nested view transition groups. But I do want to close off with this last piece right here. Oh, the second two last pieces right here. One, can you polyfill it? There's also a question I had. No. But, this is a specification.
And like we learned from earlier today, well, you can totally implement specifications. So I went ahead and I implemented it in JavaScript because this whole spec says, well, if you're going from state a to state b, like, all that crap needs to happen in between there. So I'm looking at those steps. I'm like, yeah, I can do most of that in JavaScript, not everything. So the result is view transitions dot j s.
And here it is running. And yes, it is glitchy as hell. Because if you take a look at the steps in the view transitions specification, there are some things that I can't do. Like for example, I can't pause rendering and resume rendering. You don't get to do that. Only browsers can do that. Also there, there's a bit of a thing, some things that you need to fake. So yeah, not really that.
So don't use this in production. Although two weeks later, was like, hold up, hold up. What if I only polyfill the API surface but skip all the animation bits? So don't do this. Only do the rest. And yes, the result is a view transitions mock, which you can import that says, hey, if the browser doesn't do view transitions, we're going to mock it for you.
So you import it. You register it. You're going get rid of this extra check. And then your code basically becomes this. Now this was quite an adventure to make because I needed to make sure that all the timings are the same, similar to the browser, like when you skip transitions. I also added support for view transition types.
I think this will really help you first. Now to really close off this talk is, are there old people here in the room? I consider myself old. You you might remember Internet Explorer. You go like, Internet Explorer did it first. Yes. That is true because Internet Explorer had something called interpage transitions. Just like Microsoft PowerPoint, you can now have transitions and wipes between two pages. It's like, holy cow.
This is cool. So I recorded this over an RDP session to an old box somewhere. So here you can see, like, the wipe down animation. And then you have a circle animation. So cool. So cool. And the way that it worked is that it used these two meta tags. You put it in your documents, and then Internet Explorer did it out of the box.
And you had a duration there, zero point five seconds, and you also had a transition number. And it was like one of these numbers, box in, wipe right, driver. And if you add it to magical number 23, you got a random effect from a whole list. I was like, oh, this is so cool. Let's bring the old school back.
So, yes, I built a library for that. It's IE page transitions, and you can add it to your website. You can set, like, here the the box in I don't have all the effects implemented yet in CS, but, like, the box in the box out. And then I'm going to go from random to random. So come on, hurry up, video, because we're running out of time. No. No. Yeah.
Woah. I like this. Now here, random. Random. Yes. Random. One other random. Random. This is so cool. This is so cool. Now I didn't reinvent the wheel here because we have those meta tags. So I was like, I can just throw the app retransmission rule at it and a bit of JavaScript.
And, like, yes, that's totally how it works. Like, I am reusing the existing meta tags. So browser support looks like this is not in Firefox just yet because of the MPA. Oh, I'm forgetting, Internet Explorer five one five and eight are also supported. And with that, I'm really gonna wrap it off.
I've shown you a lot of building blocks to build here. You can build microinteractions with the transitions, or you can build these curated experiences where you're going from one page to the other. So, yeah, go out there, build a bunch of stuff, Like here, elements go up due transition and so on. I really, really like this. Thank you. And if you have any questions, find me later, or my colleagues later.
Thank you, Brahmos. Madman bum raves. Yeah. Come come to the chair of interrogation, but we're only time for one Half a question. You you you you took a lot of code from Jake. Do you actually write any code yourself? That's that's from a Jake Archibald asked that,
by the way. Yes. But I I inherited view transitions from him. So before, he used to be a colleague of mine. We worked together at Google, Then I inherited view transitions from him, so I also inherited all the demos. So I think it's fine. It's fine. Yeah. He said yes.
It's fine. How are images handled in view transition? Like, I'm using a thumbnail on one page and a larger one on another. Does it cause stutter? Is it prefetched?
What what happens? A very good question. So the thing is that if you go from the one page to the other, we capture the old snapshot that is already there. But then on the new page, well, images load out of band with the rest. So the view transition will basically run whenever the new page is ready enough to render.
But that can mean that images are still loading. There is a halfway around it where you can add render blocking to it. Where you say, hey, hold up and wait until this specific element with that ID is ready in the DOM. Problem is that it doesn't work with images yet because it only checks for the presence of the element in the markup and not has the image actually been loaded.
I have a working group issue for that where I hope to feel like, hey, can we hold off running the view transitions animations until that image is ready? By the way, if you want to speed things up, check out pre rendering. Barry is here somewhere. Barry, where are you? Make some noise. You can pre render your pages.
So from the moment you start hovering a link, it can already pre render the next page, and then you cut down the the time in between your view transition.
The one more question. Okay. If view transitions have got projections projections like like when when you you demonstrated demonstrated with the video Yes. Playing, doesn't that mean that Chrome has all the ingredients required to implement Mars elements of that Mozilla only CSS thingy?
Yes. And that is also one of my personal requests that I would like to see on the web platform. If you also want it, please go to the state of CSS survey and say that you want the element function in CSS, and then maybe that's enough evidence to prove to people in the company that not only I want it, but you also want it.
So be vocal about it. As mentioned earlier today, like, the quickest way to get something in a browser is to complain about stuff. Please complain on your own blogs.
Complain directly to somebody who actually wants to be drinking a beer. That is the best way. We've got loads of questions, but no time. I'm here
all day. Find me later.
He's here later. He he gets a million euros a year salary to answer your questions. So
Can you tell my boss?
Mad man bomb raves.
People
- Dom Christie
- Jake Archibald
- Kevin Daugherty
- Maxi Ferreira
- Paul Lewis
Technologies & Tools
- Chrome DevTools
- CSS Grid
- document.startViewTransition
- element-scoped view transitions
- getBoundingClientRect
- Isotope.js
- linear() easing function
- prerendering
- Scroll Timeline
- Scroll-driven animations
- View Transitions
- View Transitions Toolkit
Standards & Specs
- @view-transition
- element() function
- prefers-reduced-motion
- view-transition-name
Concepts & Methods
- additive animations
- FLIP
- progressive enhancement
- snapshot containing block
- top layer
Organisations & Products
- Beyond Tellerrand
- Chrome
- CSS Working Group
- Firefox
- Internet Explorer
- Interop
- Microsoft PowerPoint
- React Brussels
- Safari
- State of the Browser
Works
- State of CSS
The View Transitions API can do a lot more than its documentation suggests.
Bramus Van Damme pushes it past the well-trodden paths, pairing it with
scroll-driven animations and MutationObserver triggers to unlock effects
the spec never explicitly promised.















