 Hello, I'm here to talk to you about a feature that I've wanted on the web for years now, something that has been tried many times before. But this time, this time it feels like we're really close. I am, of course, talking about page transitions. You know what I mean, right? This kind of thing. I look at this in the Material Design Guides, and it just looks really good. Not only that, it gives the user context to the navigation. It's clear which information is coming from where and the direction of travel. Whereas on the web, click pop, that's your lot. Why can't we have nice things? Well, one reason is that page transitions involve parts of the old thing and new thing animating together in perfect harmony. But on the web when you navigate, the old document goes away, and the new one arrives, and there's no opportunity for the two to work together. But that's only true with traditional web navigations. With single page apps, you're driving the state change yourself, so you can do what you want. So why don't we see lots of sites doing cool transitions between pages? There isn't exactly a shortage of single page apps out there. Well, the truth is it's really hard with the APIs we have today. Even something like a simple fade is hard. How would you keep both states alive for the duration of the transition? It's not particularly easy in modern frameworks. There's also lots of subtle accessibility and usability pitfalls. If you're going from a scroll page to a page back up at the top, how do you handle that? If either of the states contain a video or an iframe, how do you avoid their states resetting as you juggle the DOM around? What if you wanted to create a transition where this element in a scrollable container moves over to the other container? Well, that didn't work thanks to overflow hidden. To fix this, you'll need to temporarily pop the item out to the root of the page, which often means changing how you've structured your CSS. I'm not saying it's impossible, but it's not easy. Meanwhile, folks over on Android and iOS have dedicated APIs to make this kind of thing a breeze. And that's just not fair. I want some of that. So we've been experimenting with an API to level the playing field. And parts of it are behind a flag in Canary already. In fact, all the demos I'm going to show you are running in the browser. So I hope by the end of this video you'll be as excited about this feature as I am. We're going to take this basic site and use the new API to transition between states. It's a single page app because that's what the experimental stuff in Canary supports right now. But don't worry, this whole system is designed to work in a very similar way for multi-page apps. We just haven't implemented it yet. Here's a rough example of how navigations are currently handled. Let's add some transitions. First up, we're going to add a fallback for browsers that don't support this new API so things continue to work as normal. Otherwise, we're going to create a transition and start it, letting the API know when the DOM change is complete. Some of the API names here may change, but we might rename some stuff, but the pattern should remain the same. The important part is the API gets to see the state of things before and after the DOM change. And just like that, we've got this nice subtle fade between states. OK, fading isn't really interesting, so let's do something better. But to do that, we need to understand how this fading thing actually worked. First up, the browser took, essentially, a screenshot of the page, and it held it in place while we changed the DOM underneath. Then it created a DOM structure like this out of pseudo elements containing both the screenshot of the previous state and a live representation of the current state also as a flattened image. This element structure sits over the top of everything, hiding the real DOM underneath. The outgoing image fades from 1 to 0, and the incoming image fades from 0 to 1, and that's your crossfade. Once it's done, it goes away, seamlessly revealing the real page underneath. But like all my favorite APIs, this is mostly built of existing platform features, and you can mess around with them. For instance, each of these elements can be targeted using CSS pseudo element selectors, and all of the animations are driven by CSS, so we can change what they do with CSS. Like I said, the outgoing and incoming image is crossfade, so let's just set a longer animation duration. And the result of that is a super slow crossfade. All right, fair enough. But let's do more. Let's change that animation completely. First, let's define some keyframes. This slides the element out to the left, and this slides the element in from the right. Now let's use those keyframes. We'll slide the outgoing image to the left and the incoming image in from the right, just using normal CSS animations. And the result of that, not bad. There are a couple of things it could do better, of course. Firstly, it's always sliding in the same direction, even when going back to the thumbnail's view. We'll fix that later. The other thing is, well, the header, it slides out only to slide back in again. You can see that along the top. Ideally, it wouldn't move at all, since it's pretty consistent between the two states. Well, the page transition API lets us do that. We assign a page transition tag to the header using CSS. Site header here, that's just an identifier. You can pick whatever name you want. We also give it paint containment, which is just a requirement for this API. This changes how the page is captured. Previously, the page was being captured as a single screenshot. But when you give an element a page transition tag, it's captured separately, but still just as a screenshot. So now we have incoming and outgoing images for the root and separate incoming and outgoing images for the header. In the same way we've got one of these structures for the root of the page, we get another of these structures representing the header. It's now something we can target with CSS, using the page transition tag we assigned it, which is site header in this case. That means we can animate it independently of the rest of the page. Here's how it looks now. We haven't told the header how to animate, so it's just doing the default thing, which is to crossfade. And that looks pretty good. But we can do even better with one small change. See where it says HTTP, 203 in the header there? Well, let's capture that separately, too. So now we have three parts transitioning independently, the root, the header, and the text in the header. I already mentioned that the default transition is a crossfade, but I sneakily left one detail out. It also transitions the size and position of the element from its before state to its after state. And that didn't matter for the root or the header, because those are in the same place and size before and after the DOM change. But for our heading text, it does this really satisfying shift across to make space for the back button. I really like how we're making small additions and adjustments to create a transition that's super tailored to this site. Also, those three parts that form our transition, the title, the header, and the root, they have a flat structure, even though in our real DOM, the site title is in the site header and the header is somewhere within the root. They're treated as siblings during the transition. And that's a good thing. Remember this example from earlier? Doing simple DOM transitions is hard because of the nesting, but with the flat structure of page transitions, it's not a problem. OK, so things are looking pretty good here. But what about on desktop? It feels, I don't know, a bit much, like the whole page sliding across seems a bit over the top, makes you feel a bit nauseous, a bit dizzy. But we can solve this the usual way we solve things when it comes to responsive design. Here's the transition styles for the root. And here are the overrides for desktop, just using regular media queries. The main difference is they use a different set of keyframes. That means we can keep our previous transitions on mobile where the whole thing slides from the side. But over on desktop, we can have something a bit more soul, like this fade and slide. I don't know, I just made this up. I'm not a designer. You could probably think of something better. But while we're being responsive, here's the code from earlier that triggers the transition. Currently, the transition is skipped if the browser doesn't support the API. But let's also add a check for prefers reduce motion. Alternatively, you could keep the transitions, but just make them really soul for users that prefer less motion. Remember, it prefers reduced motion, not prefers no motion. But I'm just going to avoid them completely, be a bit lazy whatever. All right, what else can we do? Well, watch this. I'm going to take that large video embed there, and I'm going to make it its own layer in the transition. But this video embed only exists on this page. It doesn't exist in this page, the thumbnails page. But that's fine. You can create transition layers that only have an outgoing or an incoming component. That's a pretty common thing to do, as things appear or as things disappear. But that's not what we're going to do here. Here's the rough code for when one of those thumbnails is clicked. Using inline styles, we can say, treat this as the video embed. It isn't actually the video embed, it's just the thumbnail. But for the sake of the transition, we're saying that the thumbnail is the before state of the real video embed. And the effect of that, you ready? Thumbnail now grows into the main embed. It doesn't matter that they were different elements in the DOM, we tooled the page transition API to treat them as the same thing. So that's exactly what it did. And what you saw there was just a default transition. It moves from the before position and size to the final position and size while crossfading the images. But we can go even further. Here's an even more developed example. I've made some tweaks to the easings. I've made the video description part of the transition. I've made the sidebar part of the transition as well. And that stays fixed in some navigation cases. Maybe this is too much. Like I said, I'm not a designer. I'm just playing around with new toys. Maybe you can do better. So give it a go. This is all running in Chrome Canary using the page transition API today. I'm really excited about this feature because it's got reasonable defaults. But with little bits of CSS and JavaScript, you can make the transition as custom as you want. And really, in many ways, that's thanks to you No, seriously. We released a different version of this API last year. It didn't use CSS animations. And transitions were restricted to like a few presets. Feedback from developers made it clear presets weren't enough. It needed to be customizable. Couldn't agree more. And that's what drove the second version of this API. That's what gave us the ability to do this. All right. One last thing before I totally outstay my welcome. In this final version, the transition when pressing the back button slides from the left, as you'd expect. You know, when going forward, slide from the right. When going back, slide from the left. So how do you make the transition different, depending on that? We're actually working on higher level ways to make this easier, but in the meantime, a useful way to influence the type of transition is to add a temporary class to the HTML element. Once you've done this, you can use the presence of that class to make adjustments to the transition. But how do you know when to add that class? It's something you can totally do with the history API that's been in browsers for ages, but it's not a good API. It's really messy. However, we're working on a new API that aims to make it easy. And that's the navigation API. It's a totally separate thing to the page transitions API, but they play well together. For instance, the navigation event here fires when a navigation or traversal happens. And you can hook into this to override the default navigation. It can act as a router for single page apps. And more, like, there's loads it can do that I just don't have time to go into today. But one thing it makes easy is detecting whether the navigation is forwards or back. And that's what this code example is doing. This makes it easy to add the right class name to control the transition. And it's also what I used in the final version of this demo. Links to the demo, but also explainers, docs, specs, they're all in the description, including a code lab where you can learn even more about the API. So I guess all there is left for me to say is, thanks for watching. Bye.