Seamless Page Navigation With the View Transitions API
The View Transitions API is now stable in Chrome. That means we can make extremely cool nav animations in our web projects without extra JS overhead. Maxi Ferreira returns to teach us how it works!
Links & Resources
Full Transcript
Click to toggle the visibility of the transcript
Captions provided by White Coat Captioning (https://whitecoatcaptioning.com/). Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.
JASON: Hello, everyone, and welcome to another episode of Learn with Jason. Welcome back Maxi Ferreira. So sorry I can't roll my Rs to say your name properly. How are you?
MAXI: Yeah, thank you for having me. Excited to work on some fun demos.
JASON: The demo we did last time you were here was one of my favorites we've worked on, and it's been extremely popular. But it actually recently broke, which is part of the reason why you're back. But before we talk about that, let's talk a little bit about you. For folks who aren't familiar with you and your work, you want to give us a bit of a background on who you are, what you do?
MAXI: Yeah, my name is Maxi. I work at Help Scout as a frontend engineer. I work at what other teams might be called a frontend platform team. We work with our design system. We focus mostly on performance and frontend architecture, that type of stuff. On the side, I like to work with sort of like platform APIs. I like to test new APIs, new frameworks, and one of the APIs that I've been playing with the most recently is the view transitions API. So if you follow me on Twitter or you might have seen some of my demos on Twitter, I just find it really, really fascinating and fun to play with APIs. So I just love to spread the word about it.
JASON: Excellent. Give me just one second. I'm getting an echo, and I'm not sure why. Can y'all -- let's see. Give me a quick check of your -- wait, it's fixed? Or is it back? Maxi, can you give us a quick mic check?
MAXI: Hello, hello. Still hearing the echo?
JASON: Hold on one second. Let me try to get this fixed. I just moved my studio. If you've seen the show before, you might recognize this is a new space. So I am attempting to fix this in a way that doesn't cause bad load back. So Maxi, one more check?
MAXI: Hello, can you hear me?
JASON: How is that, y'all? Okay. That's better. All right. Sorry about that. And we are now in business. Okay. So, good. All right. So yeah, you've been working on a lot of this stuff. So the demo that we did last time was for an API that has been renamed. It was -- I think at the time it was called the shared element transition API. Is that correct?
MAXI: Exactly, yeah. That's one of the things I changed. It's now called view transitions. Other function names and things have also changed. That's why the API broke on us.
JASON: Got it, got it. And so let's go at a high level. What is the view transitions API? What problem does it solve?
MAXI: So yeah, the main problem that it's trying to solve is to allow you to do kind of animate and transitions between navigations, right. So whether you're on a single-page application or a multi-page application when you navigate to a completely different document, this API allows you to do that transition in a sort of seamless way with a nice CSS controlled animation. It can be used for other things. So I think the API has sort of two parts. One is the same document, view transitions part, which is everything you can do with JavaScript on the same document. You can transition different elements on the page. That doesn't necessarily need to involve a page transition. So we can play with some simple demos now with just changing an element on the page from one place to the next. Then there's the cross-document API, which is the new part. This part didn't exist last year when we were talking about this API. We didn't have this. So this is new.
JASON: This is what we had to fake, right? We had to bring in, I think, turbo links, so we could simulate a single-page app to get these transitions. So you're saying that's built into the browser now? We don't need to bring in a JavaScript library to do single-page app. We can do it with a multi-page app.
MAXI: Yes, that's the part. That's still experimental for now, this multi-page application support. But it's -- sort of the SPA version, which was experimental last year when we were playing with this, we had to enable a feature flag. Now it's enabled in Chrome by default. So if you're using Chrome, you have this feature enabled now. You don't have to enable anything.
JASON: Got it. Got it. Well, that's super call. I'm really excited about just the whole possibility of all this. It's such a cool -- let me just start this over because I just tangled my thoughts in my head. I'm very excited by this because one of the reasons that I think people have had a hard time with multi-page apps is when we introduce single-page apps and introduced mobile applications, we suddenly got used to this idea that when you navigate, you don't see a page refresh. You see, you know, sometimes just the content refreshes in the main window, and you have the header navigation stuff. Then when you look at really nicely designed apps, you actually see these beautiful transitions where an element will move from one section of the page to the other. Without a way to do that in multi-page apps, that's a significant downside of moving away from a single-page app architecture. And one of the kind of most valid reasons I think people push back on this idea of, well, why don't you just use an MPA, you don't need JavaScript, it's like, well, I need that app UX of moving between pages seamlessly. So why I find this so exciting is that it actually gives us a valid path forward to get that experience of an app-like navigation, an app-like experience of using the app without having to bring in more JavaScript. So there's, theoretically, a world here where between the new CSS APIs, a lot of the new browser APIs, you could potentially build an entire app that doesn't ship any JavaScript and feels like a mobile app.
MAXI: Yeah, yeah, exactly. That's one of the main benefits, just shipping less JavaScript, doing sort of less work on the main thread as well. A lot of this -- there are a lot of tools for doing transitions on an SPA, but they're going to plug the main thread. So having this sort of built-in support, not having to pull in a third party to do this type of thing, it's also really great.
JASON: Yeah, that's extremely exciting. Okay. So right now, this is the -- the view transitions API is partially stable. You said the SPA support is stable, but it's still currently only in Chrome Canary? Or is the SPA part in all versions of Chrome-based browsers?
MAXI: It's on all versions of Chrome-based browsers. So it should be if you're on Edge or Arc, in Chrome-based browser should have this enabled.
JASON: Oh, that's very exciting. And so the piece, the experimental piece is the multi-page, like navigating between pages. For that, we need Chrome Canary, is that correct?
MAXI: Yeah, exactly. We need Chrome Canary.
JASON: Okay. And so this is one of those if you want to experiment, you want to play, definitely try this out. But do be aware the multi-page stuff isn't going to work in all browsers just yet. And similar to when we played with the shared transition element API last year, it's subject to change. As the team learns more about how this works, we might see that multi-page app setup shift a little bit. Okay. So part of me just wants to jump into this and start coding, but I feel like -- is there anything else -- like as you've been building with this, what are you finding feels the most magical about this API?
MAXI: I find it super interesting that you can do -- like, I was mentioning, you're not sort of restricted or limited to page transitions. You can do, you know, element transitions. You can do sort of like flip animations when you want to reorder in some fashion. So if you want to do that with traditional technologies, you need a bunch of JavaScript to calculate the position of the new elements and then move them around. Doing that type of animation with this view transitions API is very simple. We're going to see an example of how we can do that. I'll say if you have too many elements on the page, it's probably not the best thing because right now there are some sort of performance problems that the team is working on. So you have to try not to have hundreds of elements on the page moving at the same time. But for simple flip transitions where you want to move some boxes around on the page, it's really great because you don't have to worry about anything, really. The browser takes care of sort of morphing the elements into the right places. Yeah, that to me is one of the things that I don't use very often because I mostly use it for page transitions. I want to transition from one page to the next. But this also is a really nice feature. Another thing -- as I'm talking, I'm remembering another thing that's very cool is last time we talked about the -- so when you do a view transition, the browser is basically taking two screenshots of the before and after states of the page. Then it will transition between them. But the cool thing is that sort of the after screenshot is not really a screenshot but sort of a live representation of the dom. So if you have a video playing or a GIF or some animation, it will continue to play during that transition, which is very cool. It allows you if you have video playing, you want to do a picture-in-picture type of animation, the video will continue to play. So it's not like you're in a frozen state while you do the transition.
JASON: That's super cool. I mean, I love -- that immediately got my wheels turning on cool things we could do where if we can do something like that, then you could theoretically have the Learn With Jason site -- right now the stream is being live cast, but it's only on one page. But if we had this, what we could do is on every page, you could have the player in the bottom right corner whenever we're live. Then when you go to the page where it's full size, it would animate to full size. When you navigate away, animate back down. All of that would be possible with -- I mean, we'll need a little JavaScript to get the player working and stuff. But eventually when we get the multi-page in full support, that's -- like, it just works. That is magical. That stuff is so cool. I'm just -- you know, this is one of the spaces that I think is maybe one of the most exciting in the web that's getting the least amount of hype. This rapid advancement in the browser. The amount of stuff we can do with browser APIs today is so incredible, especially compared to what I remember back in the day where you spent all your time as a dev sort of wrestling with browser inconsistencies. Now we're seeing browser APIs steadily pull things in that are universally supported. I mean, partially because just about everything is Chromium. But even on Firefox, there's excellent parity. But you have these long-livid, stable, effectively future-proof APIs. When something ships in the browser, it's not going to break. The browser doesn't break backward compatibility. We don't talk enough about that because I've spent way too much time going back and fixing something because the framework shifted and changed its API. Now my stuff is broken if I try to update to the latest version. But in the browser, that's just not a fear, unless you're using something experimental. I just love it so much. So anyway. How about we jump in and actually play with this a little bit?
MAXI: Yeah, yeah. I'd love to.
JASON: I can't wait.
MAXI: And I thought we can actually start with sort of like the very basics, to talk about the API, just a very minimalist, simple demo to see how things work and implement it in an actual project.
JASON: Perfect. Awesome. All right. So let me really quickly just give a shout out. This episode, like every episode, is being live captioned. We have White Coat Captioning. Rachel is here today. Thank you very much for being here. That's made possible by the support of our sponsors. We've actually got new sponsors. I just haven't updated this part of the site yet. We have Netlify staying on. Then we've got Nx, New Relic and Pluralsight wrapping up the last quarter, the end of their sponsorship. So thank you to them for all they did. I do have a couple spots available if anybody is interested in joining as a sponsor. We're talking to Maxi today. Make sure you go in and do a little follow over there. Okay. So with that being said, I think you wanted me to be using Chrome Canary today. I'm in Arc right now. Do you want to start here and move over later?
MAXI: We can start with Arc right now. Any Chrome-based browser should work with this.
JASON: I think I used GitHub for -- yeah, great. So then I can create a new pen. Do you want me to do anything with a template or just go in?
MAXI: No, just regular HTML. We're going to use HTML and CSS.
JASON: Okay.
MAXI: So let's start with a box. Let's do a little red box or blue box. And we're going to see how we can sort of animate that with just a tiny bit of JavaScript.
JASON: Oh, I can use this. And background.
MAXI: Oh, nice. Perfect.
JASON: All right.
MAXI: Now let's declare sort of like a clicked version or a clicked class for this box where we're maybe going to move it to the right a little bit.
JASON: Okay. Should I use relative position, or what do you think?
MAXI: We can do either. Yeah, just left, 300 pixels or so. I guess we have to do position absolute or relative.
JASON: That should work. So then if I add this --
MAXI: Yeah, perfect. That's perfect.
JASON: Okay.
MAXI: Now let's do some JavaScript to actually apply that class when we click on the box.
JASON: And we'll do a document.queryselector. Then we can box.addeventlistener. Okay.
MAXI: Perfect.
JASON: Look at it go. So then --
MAXI: Yeah, toggle. Perfect. So now we can actually do a transition. So what we can do is wrap that call to the toggle of the class in a transition. So we can do document.startviewtransition. That takes a call back. In that call back, we will do the dom update, which in this case is adding that class. And if we try it out now, we should see a nice little fade-in, fade-out animation.
JASON: Look at that. Okay.
MAXI: So what's happening here is, as I was mentioning before, when we make the call to start view transition, the browser sort of takes a screenshot of the page, of the entire page, not just the box. Then it calls that callback that we are updating the dom. At the end of the call back, it will take another screenshot. Once you have the two screenshots, it will sort of transition between them. The default transition is to do this fade in, fade out. So the old screenshot will fade out, and the new one will fade in at the same time. That's why we see that animation. We can control these with TSS, but what we can do as well is we can tell the browser that a particular element, so in this case our box, is the same element both on the old screenshot and the new screenshot. So the browser will say this element moved. So I'm going to move it to the place where it's on the new screenshot. To do that, we have to apply a view transition name to the box. So on the CSS, we can define a property called view transition name. We can give any name, as long as it's unique.
JASON: Oh, my god. That is so wonderfully simple. Like, it's just brilliant to me you can do something like this in, what -- so including the wrapper, three lines of code. We took something that was originally very, like -- it popped. It's an instant change, which is fine. We use apps like that all the time. But with three lines of code, we made it into this nice, actual animated transition. And I can't really think of any other way you could do that. I guess for this one, you could set the transition to, you know, 200 milliseconds or whatever. But that's not going to hold up when you start modifying the actual dom.
MAXI: Exactly, yeah. For certain things, we can do like translate -- animate the translate position and things like that. But this will take care of a bunch of things for us. It automatically translates color. If it disappears from the screen and appears again, we can control those sort of like enter and exit animations individually. And yeah, like you said, to me this is a perfect example of a really good abstraction. It's very simple. We just called a function, applied a CSS property, and we have a really powerful feature now in our hands. We can customize it with CSS and do other stuff, but the API surface is very simple. We didn't have to do much.
JASON: I saw a question in the chat just now asking about is there any sort of keyframing available. So can you do anything complex with these, or is it sort of pretty simple stuff?
MAXI: Yeah, you can customize the transition with keyframe animations. So you can find a custom keyframe animation in CSS and apply that to the transition.
JASON: Nice. And is this smart enough that if I, like, rotate 180 degrees, will it -- look at it go!
MAXI: You can change color. You can change the size as well. So we can play around with some things. And it will transition all of them.
JASON: So cool. I also love that this is a top-level property now, instead of having to be the transform with a million subproperties. Such a nice little upgrade.
MAXI: Yeah, that's right. Okay. And one way we can also sort of control this animation is with a selector of a pseudo element called view transition group. So we can define a new sort of CSS selection. View transition group.
JASON: Is it double?
MAXI: Yeah, that's right. It's double. Then in parentheses here, we have to pass the name of what is the element that we're controlling. So in this case, it's the box. And here is where you can define your custom animations. If you want to do something simple, we can just say animation duration to like three seconds or something. We'll see how it will still use a default animation, but it will be much slower. We can play with the timing function. So just a custom easing function and things like that as well.
JASON: Animation timing function. Is that right?
MAXI: Yeah, I think so. You can do like easing out or one of those. So it kind of slows down at the end.
JASON: Mm-hmm. A little more organic.
MAXI: Yeah, I can actually give you this one. Let's see if that works. I'll paste one in the chat. That should be like a sort of bouncy animation. It goes to the right and comes back.
JASON: And if we take this back down to the default -- oh, that's way too fast. Maybe take it down to like one. Look at it go. That's pretty fun, right?
MAXI: It's pretty cool. We can also sort of inspect the animation in dev tools. So if you go to -- if you pop the animations panel. You have to hit escape. Yeah, there you go. Oh, there's that kebab menu.
JASON: Let me pull this to the side so we can see it more easily. Then we have our animations tab here.
MAXI: Yes. So now -- is that the animation?
JASON: That's the wrong one. Where's our box?
MAXI: So you can parse the panel and click on the box. Now you can scroll.
JASON: Ah, here it is.
Louise: Scroll the little pink bar to the right, and you can control the animation.
JASON: Oh, cool. That's dope.
MAXI: It's very useful, especially when you have multiple elements on the page, like transitioning at the same time. It's really cool to see, you know, what's going on, on the page.
JASON: Well, yeah, just being able to -- all right, I'm 250 milliseconds in. Where is everything on my screen? I do this all the time where I'm like trying to get three things to look natural as they move together, and it doesn't. So I just have to bump by ten milliseconds at a time until it starts to feel right. This, I had no idea this panel was here. I'm feeling foolish because I could have saved myself a lot of heartache.
MAXI: Yeah, it's super useful. I don't work with animations too much, but if you are -- I know that designers love to sort of customize the animation down to the millisecond, like you were saying. Everything has to be perfect. And this is a very cool tool to do that. You can also control the delay for your animation, things like that. And on the left, we now see here all those different -- on the bottom left, you see view transition. These are all the different pseudo elements that the browser adds to the page when we do a transition. And we can sort of customize each one of them with CSS. If we go to the elements tab -- oh, we are on the elements tab.
JASON: Yeah, I got to pull this down so we can see.
MAXI: So we can see them there at the top.
JASON: Oh, cool. Okay. Yeah.
MAXI: So those are added only during the duration of the transition. When the transition finishes, they get removed.
JASON: Got it. Okay.
MAXI: Cool. So now that we have the basics, we can jump to the more sort of real-world demo. I have a repo here I prepared. So let me --
JASON: For this one, I should open up Chrome Canary, right?
MAXI: We can stay in Arc for the first part. Well, we can jump directly to Canary if -- because we're going to need it for the second part when we talk about this cross-document transition.
JASON: Yeah, why don't I minimize this, and I will pull up Canary, which I put here. And you sent me a repo.
MAXI: I will spend you the repo. I will also share it on the Twitch chat, if I can open it.
JASON: I'll share it here. That's also puts it into my automatic link saver. So here's my link. Everybody bear with me while I get signed into all of my accounts. Am I even going to need this, actually? You know what, it happened so fast, it doesn't matter.
MAXI: Yeah, I don't think you're going to need to sign in. We're just going to clone the repo and just start to play with it locally.
JASON: Okay. So let me open up one of these, and we will do GitHub. Repo clone.
MAXI: I see someone else in the chat discovered the animation stuff. Chrome dev tools have so many hidden features. I was watching a talk a couple months ago. So many things. He shared like a hundred tips for the Chrome dev tools.
JASON: Incredible stuff. Like, it really is one of those -- it does so many things that you can spend a whole career trying to become an expert in it. It's like any other sufficiently complex piece of technology. The 80% is pretty fast to learn. That remaining 20% can take you the rest of your life.
MAXI: Exactly, yeah.
JASON: Okay. So I've got the repo open here. Oh, wait. Let me actually open this folder. I just cloned it. I didn't actually open it. So I'm going to go into GitHub. There it is. All right. So here's our site. It is a -- I think I saw it's an Astro site.
MAXI: It is. It's an Astro blog. Very simple. It's based on a template that is on the Astro website. I think it's called tableau. I remove a lot of things from the template. We only have two pages now. We have a homepage and -- I think you're missing a zero.
JASON: Okay.
MAXI: So you have like a homepage, and then you can open one of the articles. That's it. Two pages.
JASON: Okay.
MAXI: And can you -- let's see. Can you resize the browser a tiny bit? There go. The first demo we want to see this grid layout. So if it's only -- yeah. What we're going to do here is sort of like a filter. So the first part, we're going to play with this JavaScript API for sort of same-page transitions. So we want to use what we saw before on the CodePen to sort of filter this list of elements in a nicely animated fashion.
JASON: Oh, right. Because we can click down.
MAXI: Exactly. That's only partially implemented. So we have to finish implementing that sort of list. So that is in a React component. This entire -- it's called tag selector. There you go. This entire website is just Astro components, except for this component. So we're going to have to do some hiding. So yeah, the first thing we want to do is finish implementing this use effect. So we have the list of articles on the page there. We're just going to, you know, hide the ones that don't have the selection.
JASON: Got it. Okay. So the article category is the selection.
MAXI: So the selection contains the selection of -- we can actually console log this if you want to. So when you click on one of those tags, it will be added to the selection.
JASON: Okay. So then if I put this out, I'm going to put this back at the bottom. We'll head to the console. We get our list of these. As we add things, we get a list. Okay.
MAXI: Yeah, just basically a list.
JASON: That makes sense. So the work we need to do is in our articles. We want to probably map over them, right?
MAXI: Mm-hmm. And then the articles contain the category or their tag in a data attribute. So you can access the category.
JASON: If I look down here, I can see the span.
MAXI: Oh, that's in a different -- yeah, that's in a different component.
JASON: This is correct, though?
MAXI: Yeah. I don't know if data or data set. I use data set, but I don't know if --
JASON: Oh, it is data set. You're right. So then we can say if the selection includes --
MAXI: Yes. Yes, it's include.
JASON: Then we can add article.classlist. Or no, remove.
MAXI: Remove the hidden class. Exactly.
JASON: So then, theoretically -- articles.map. Do I need to do something?
MAXI: This is not completely an array. It's an array-like type of thing. So click on one of the tags, and this should -- yeah. So I think what we should consider now is the empty state. So when we have no tags, no selection.
JASON: So then I need -- so we can just do, like --
MAXI: We can add that to the if.
JASON: I was just going to say if selection length is less than one, we can just return. So we won't add anything. That way, we should get our category. Is that going to work? Or do you want me to do it a different way?
MAXI: I think if you unselect technology -- if you click on technology again, it will not filter.
JASON: Oh, it breaks, doesn't it.
MAXI: So I think the ifs can be like if not selection.length. Or the other thing.
JASON: Okay. So let me -- oh, boy. What's happening?
MAXI: Then we have to remove the class hidden as well.
JASON: Oh, got it. Okay. I guess we could do it like those.
MAXI: Exactly. And I think this should work now.
JASON: Empty, filtered, empty. Great. So if we look at this in the grid view, we can see that a little more obviously. Things are being filtered as expected.
MAXI: Yep, nice.
JASON: Okay, great.
MAXI: So now what we can do is we can wrap our logic inside of a transition. So we can do like document.startviewtransition.
JASON: Is this right here?
MAXI: Yeah.
JASON: And this is going to be our wrapper. We'll move the whole thing in. Then would you do it like this? Or do you want to do it kind of around the outside?
MAXI: I think either way it works. Yeah, we can do it around the for each maybe.
JASON: Yeah, let's do it around the outside. This would start it again for every dom element. I have no idea if that matters, but this at least we're just doing it once.
MAXI: Yeah, that would actually give us an error probably because I think we can't start a transition while another transition is happening.
JASON: Look how nice this looks.
MAXI: Really, it's pretty nice, right?
JASON: You just don't have to do anything, and it already feels so good comparatively.
MAXI: I know. It's so cool. You can just sprinkle these view transitions around. It's magic.
JASON: Yeah. I can already feel this is going to become a central part of the way that I work. It just makes such a small difference but such a good difference. And it really feels wonderful to work with this.
MAXI: It's also really good for backwards compatibility. You have to check if it doesn't exist. Then you have to do the dom update manually. But other browsers would just not have the animation, but it would continue to work.
JASON: Yeah. Oh, dang. So cool. So, so cool. Okay. So actually, why don't we show how to do that really quick. If we wanted to make this, like, we would say filter articles. Then we would take each of these and put this up in here. Then if we want to check, we can say if start view transition in document, then we would document start view transition, and we would filter articles. Or else we would just filter the articles. That way we have backward compatibility. It's still going to work even if the browser doesn't support this yet. So it's a little bit more code, but now we don't have to worry about backward compatibility. This will function in every browser as far back as we can probably support these days, right?
MAXI: Yeah, yeah. We're not doing anything special. Then the CSS, if we add any custom CSS, that will just get ignored by the browser. So yeah, this will work everywhere.
JASON: Incredible. Okay. So what's next?
MAXI: Nice. So now what we can do is we can use the view transition name tag, CSS tag. We can apply one for each one of these cards. Then instead of doing this fade in, fade out, we can just move them around on the page as we filter. So to do that, we have to go to the card.Astro component. I guess we can do it with JavaScript as well. But we're just going to apply probably to that wrapper div. We're going to add a style tag. We're going to set this view transition name to -- we need a prefix. So like image or card.
JASON: And I need to make this into one of these. Oh, come on.
MAXI: There you go. So we need a prefix because the name needs to start with a letter. It can't start with a number. And some of these logs start with numbers.
JASON: And this is also just kind of a CSS style. Like a prefix to help you logically group things if you're going to debug them as well.
MAXI: Right, exactly. Yeah.
JASON: Okay.
MAXI: So with this, let's see how it looks with just adding this. It should start to move things around already.
JASON: Oh, beautiful. Look at it go.
MAXI: Yeah, everything goes to the right place. We didn't have to do any JavaScript. We only added that CSS property.
JASON: Oh, it's so cool. It's beautiful.
MAXI: It's very cool. Very cool. And we mentioned before, we only have I think 15 articles or so on the page. If we had hundreds of pages, hundreds of articles, then we should probably do something like only add this view transition name, you know, when you need it. So we would do this with JavaScript, for example. But in this case, it doesn't affect the performance.
JASON: Yeah, then there's a question in the chat about getting seamless transitions in Astro with the view transitions API. I think we're about to do that, right?
MAXI: Yes, yes. We're going to do a --
JASON: So, sit tight. We're about to show you.
MAXI: Yeah, we're going to have a page navigation transition as well. But for now, I want to also take -- like, now that we have this nice sort of transition on the same page that we have here, we can play a little bit with adding some CSS rules to customize the enter and exit animations that we apply.
JASON: Okay.
MAXI: So there's a styles CSS file that's empty. Yeah, should be empty. And here we're going to start by defining a couple keyframe animations. We're going to define one called scale out, and that will be -- that will have a two property block that should set the scale to zero. Then we'll define another one that will fade in that will set the opacity to one. We don't need to define the from here because it will use whatever is the system opacity and scale.
JASON: Okay.
MAXI: And now we want to define an exit animation. Let's say when one of those cards disappear, we scale it out. So what we can do is we can target -- we don't need to define a new keyframe. We can use the scale-out keyframe. But we can target the pseudo element view transition. Remember we had all those view transition dash something. This is called view transition old. This is sort of the old one. And here we can set the animation to scale out.
JASON: Do I need to set any -- I can let everything else be default, right?
MAXI: Let's see how it works. Maybe everything uses default. Or maybe we can set the animation name. Oh, we're missing something. We need to path in parentheses which are the elements. In this case, we target everything, which uses an asterisk here. We're going to try this out now.
JASON: It kind of worked. It got a little weird.
MAXI: It got a little weird. But there's a little weirdness. We're missing one more thing. So we want to define the exit animation. And now to do that, we need to target this old screenshot only when there is no new screenshot for this element. So we can do that after the asterisk, or after the closing parentheses, we can do -- sorry, outside of the parentheses.
JASON: Oh, oh. Got it.
MAXI: We can do colon, only child. So the reason this works is there's an image pair sort of view transition group. That contains the old screenshot and the new screenshot. When the old screenshot is the only child, we know this is an exit transition because there's no new screenshot. Let's do -- yeah, let's try that. See if that --
JASON: I'm trying to take shortcuts. There it is.
MAXI: Yeah, I think you see that scale out. We can also do animation duration.
JASON: Now you'll see it's much slower.
MAXI: We can also customize the animation. Now we're targeting the new screenshot. That's also only child because we have a new screenshot, but we don't have an old screenshot. Let's try fade in. Oh, the other elements are moving fast. So we should probably do -- let's do a view transition group. Yeah, let's do a selection for view transition group. And also set the animation duration to one second here. We need the asterisk as well.
JASON: Oh, right, right.
MAXI: I'm not seeing the fade in.
JASON: Yeah, it's popping in, not fading in. I think that means I messed something up. Do I need to set a default opacity or anything?
MAXI: I don't think we need to. Oh, maybe we do. Let's set the from opacity to zero and try that. Yeah, I think that's much better.
JASON: There it is.
MAXI: You can also, of course, do a scale in. So if we want to also customize -- yeah, we can apply both a fade in and scale in.
JASON: Then for this, should I add a new --
MAXI: Yes, we can do that. We can also do the scale out and do the reverse.
JASON: Can you double like that?
MAXI: Would that work?
JASON: Like put in two animation names.
MAXI: I'm not sure if that works. We can try it. The way that I tested this was to do the entire animation. Did it work?
JASON: Okay. It did not. I don't know if that's because I got the syntax wrong or what. But why don't we just drop this right down here.
MAXI: Oh, yeah.
JASON: Then I can scale from zero as well.
MAXI: Yeah.
JASON: Beauty.
MAXI: Looks very nice.
JASON: And that's great. It feels immediately very appy.
MAXI: Yeah, exactly. And we only did some CSS. We really only added one line of JavaScript in this entire thing.
JASON: And I can actually leave those out now.
MAXI: Yeah, that applies to everything.
JASON: Great. This is awesome. Okay.
MAXI: One limitation of this API that I know the team is working on, so this is something that might be coming soon, is that the only way we can sort of select which screenshots we want to control is either globally using the asterisk or by name to refer to a specific element. We can't do sort of by group. Let's say I had other elements on the page, but I only want to apply this to our cards, for example. That is not supported at the moment. So if we try to do card, dash, asterisk, to match the cards, it won't work. So that is coming out. I'm pretty sure the team has received a lot of feedback about this. So I think that's something coming up.
JASON: Cool.
MAXI: Okay. So now I think we can jump to the new stuff, which is the MPA support for view transitions. For this, we actually need to enable a feature flag in Chrome Canary. So you can go to Chrome flags. Search for view transition. And that one, yes. The one for documents.
JASON: Okay. Relaunching.
MAXI: Yep, perfect.
JASON: All right. And there we go.
MAXI: Yep. And the way we enable this is very simple. We just have to go to our layout.Astro file, which contains our HTML layout. We have to add a meta tag here in the head element.
JASON: Okay.
MAXI: So anywhere in the head, we can add a meta tag. The name is view transition. View-transition. And the content is same origin. I'm not sure if there are other options available. I think same origin is the only one supported right now. And with that, we already have -- so if you navigate from this page to a blog post, we should already see things animate. And this is not an SPA.
JASON: Watch, watch. Everybody watch. I'm clicking the forward and backwards buttons and getting transitions, and it's updating -- like the URL is changing. So this is a multi-page app.
MAXI: This is a multi-page app. There's no -- we can disable JavaScript if you want to prove it.
JASON: That is freaking cool. Okay. JavaScript is disabled. I'm going to reload for good measure.
MAXI: Oh, we got the white because there was a JavaScript plug-in. But yeah.
JASON: Look at it. Yo, this is so freaking cool that just works. I don't even know how to -- ah, I love it. I love it when the browser just does these things. Okay. Can we talk for just a second? If you were going to implement this in JavaScript today, how much work would that be? Like, how much effort are you going to put in to making this thing function? Like, you've got to pay attention to the browser history. You've got to pay attention to where things are on the page. You've got to add these effects to, you know, do the flip. What is flip? It's first, last, invert, play?
MAXI: I think so, yeah.
JASON: I think that's what -- hold on. Let me verify that I'm right on that.
MAXI: You have to remember what flip means. That's another thing.
JASON: Yeah, you have to remember what it means. Let's see. Flip animations. Has anybody defined it? You know, it's okay.
MAXI: Oh, flip your animations. I think that's one of the OG articles. There you go.
JASON: First, last, invert, play. Oh, my goodness, my memory is a steel trap. (Laughter)
MAXI: Nice work.
JASON: But yeah, you have to do all this calculation where you know the start point, you know the end point. You have to work backwards to figure out how to get it from the start point to the end point. Then you have to do that calculation, set up an animation loop. You can get plug-ins and stuff to do this, but then you have to catch the page navigation, and you have to simulate the page navigation using something like a router. So you're either building all this yourself, which is a huge pain, or you're grabbing different libraries to make these things work, which is fine individually until you're trying to get the libraries to inter-op, in which case you find yourself in a custom hook or use effect or whatever kind of tricky situation. All of that, like hundreds of lines of JavaScript, just disappears with a meta tag. What absolute magic. Like, oh, my goodness. What a great time to be alive.
MAXI: It is a great time. Yeah, some people call it -- I know that for CSS, a lot of the features coming with CSS, they call it like a CSS golden era. There's really a lot of features coming to the platform. Like the scroll-driven animations. Of course, view transitions. There are new elements coming. So it's a really great time to be a web dev.
JASON: Yes. Okay. So we added the one meta tag and got the cross-page transitions. What else? Like what else should we see here?
MAXI: Well, we can do what we did last time. When you open one of those articles, the header image exists in both the thumbnail and the article. So what we can do is similar to how we did with our box, in our original CodePen, we can say these two elements are the same element, actually. So I want you to morph them in place, move it in place in stead of fading one in and fading the other out. And we do this by just applying the same view transition name to both elements.
JASON: Got it.
MAXI: So one is in the card component. If you go to the card.Astro component, you will find --
JASON: We are doing it with the --
MAXI: Yes, we have that transition name for the entire card. So we can define a new one for just the image.
JASON: Oh, I understand. So this is my image. I want the picture, right?
MAXI: Yes, we want the picture, and we want to apply a transition name to this image. So instead of card, it can be image. Yeah, exactly. Now we want to apply the same name to the same -- yeah, the same tag to the card in our blog post, which is in -- what's the name of the file? I think it's log. So there's the other picture. This is the full-size picture of the blog post.
JASON: All right.
MAXI: So now by doing that --
JASON: Everything is still working. Oh. Oh. So good. Okay. So one thing that I just noticed is this one seems to be beneath. Is there a way I can change the stack order and put that one as higher Z index or something?
MAXI: Yes, we can. So this is one of the things we'll probably have to do dynamically. We can either remove the transition names from the other elements, or we can apply it like a higher Z index to the one we're clicking on.
JASON: That's what I was thinking. We could do the higher Z index. And to do that, we just need to do that in JavaScript?
MAXI: I believe so because you need to know which one is -- unless we can do it with CSS. I haven't tried it. I guess we can use maybe the active pseudo selector.
JASON: Yeah, so let's go with active.
MAXI: Although, I'm not sure that will work. What we want to do is define the higher Z index on the view transition screenshot, but that doesn't get an active state. That's just a screenshot.
JASON: But it would be within, wouldn't it? So if we did active --
MAXI: It's not within because those are at the top.
JASON: Oh, you're right. Okay.
MAXI: That is a good question, though.
JASON: So we would need to do something like just a little bit of when you click the link -- I think this is pretty straightforward to solve. Let's do this. Let's do a script. Inside of it, we're going to do a document.queryselector all. If it's a link like this, we will then say -- no. Add event listener. So what we're going to do is -- oh, I have to do a whole --
MAXI: Yeah, I think we need to do it for each one.
JASON: Fine. Okay. So then I'll add my link, event listener, and then we will say E target query selector image. Then styles index equals -- wait, as is tradition. Okay. But I've done it wrong. Can I just do it like this? No. Okay. Fine. Still doesn't like it. It's not possibly null. How dare you. We'll just do one of these. Come on. How about that? How about you hush. Oh, come on. Well, you know what time it is.
MAXI: Time for TS ignore.
JASON: Get out of my code. (Laughter) All right. Let's see if this works then. Oh, I did it wrong.
MAXI: So because you're applying the Z index to the image, but what's transitioning here is not actually that image, it's a screenshot of the image.
JASON: Oh, you're right.
MAXI: But what we can do is we can set -- instead of applying the view transition name to all the cards or to all the images, we can apply to only the image that is going to transition. So we can do here the same selector you have except instead of applying the Z index, we're applying the view transition name. Does that make sense? I think that should work.
JASON: Yeah, so we're going to view transition.
MAXI: We can set this to image active. And we need to match that in the -- oh, we were in the slug. We should probably do this on the index page, right?
JASON: On the index page only?
MAXI: I think so, yes.
JASON: Okay. That I'm going to look in here real quick. Index, yep. Then we'll drop it down to the bottom. So that will update the clicked one to have image active, which means that in slug, I need to change this to be image active. Is that right?
MAXI: Yes.
JASON: Okay. So instead of being one of these, it'll be one of these. And theoretically, it will break entirely because I did something wrong. Let's have this console log and make sure I actually did a thing. Here's my index. I can also give up on this if you had something else you wanted to show. I don't want to burn the rest of our time trying to debug this.
MAXI: No, I'm fine. We can also do -- let's see. I think this is important also to show. We can show very quickly sort of how to disable or adjust some of these animations for users that might have the reduced motion setting enabled on the browsers. Oh, is it style instead of styles?
JASON: Cannot read properties of null. So it's actually not finding our -- oh, the target is the image. Fascinating. So if I click here, though, it's the span. So then I would need to bubble up. Oh, this sucks. (Laughter) Okay. So we'll have to find out how to get up to the parent. So this is a fun loop. Is there a way to do --
MAXI: Well, if we do current target --
JASON: Current target.
MAXI: That should be always the anchor tag. Yes.
JASON: That is always the link. Okay. So that's what we want. I'm going to turn off the prevent default. I'm going to turn this off. Then that, theoretically, okay.
MAXI: It is what we want. Now we still need to remove all of the other -- we're still applying the transition to all the cards.
JASON: Right. So back to the styles.
MAXI: So if you go to the index and where we're applying that style.
JASON: Oh, it's in the cards, right?
MAXI: Yes, in the cards.
JASON: So we're going to take this out.
MAXI: Let's remove the one on the card as well, just to see if this works. Then we can figure out how to -- so there's one at the top.
JASON: Of course that doesn't work. I know how undo works. So I'm just going to do one of these.
MAXI: Yeah, we broke this, but it should fix the other one.
JASON: And it does. This now looks like what we want, where it pops in. Then if I come out here and grab one of these, it goes to the right place. So this looks really good. Okay.
MAXI: But we lost the other ability. So I guess -- why don't we do the inverse. Again apply the style to the card and the images that we had before. We roll back. And apply to all the images as well. Then on the click event, instead of adding one tag, we are going to -- yeah, let's also roll this one back, the one in the slug. To use the slug, yeah. So now here instead of adding one, what we can do is let's remove all the view transitions. I don't know how much work it's going to be, but let's remove all of the other view transition names from all the other elements except for this one image.
JASON: Oh, I got you. Okay. So then we would have the current target, we would get the image. You want to do it on all the cards?
MAXI: Everything that has a view transition tag applied.
JASON: Okay. So the way that the cards are set up is we've got the style view transition name. So to target those --
MAXI: Let's target -- this has the class article. We can do all articles and set the view transition name to undefined or something.
JASON: Class articles. That's going to be document query selector all. And then we can do articles for each. Article.style.view transition name equals off.
MAXI: Yep, and we need to do the same thing for all the images as well. Yeah, for all images inside of the articles. Yeah, exactly.
JASON: Article is possibly null. Style does not exist on type elements. That seems -- what am I -- oh, TypeScript.
MAXI: Is this going to cause a build error?
JASON: It really shouldn't. This is functional. What am I doing with this one? So I don't really need this image anymore.
MAXI: Yeah, but we need to apply it. We're going to remove it also from the image we're clicking. So we need to reapply to this image.
JASON: Got it. Okay. So then we will image.style.view transition name. And that one is image.
MAXI: We can actually save the previous view transition name. Save that in a constant or something.
JASON: That's going to be image.style.view transition name. I'm embarrassed to say that would have taken me days to figure out. All right. So let's try this again.
MAXI: See if that works.
JASON: These work. They do what we want. Okay. Come back out here.
MAXI: Nice.
JASON: Beautiful.
MAXI: Go back. Nice.
JASON: Look at it go. This is gorgeous. This works so nicely. The forward and backward buttons don't cause the application of those things, but I think I can live with that. This is great. This looks wonderful. I can see a lot of ways I would want to continue tweaking this and trying new things and figuring out more that I can do with it. Do you know, off the top of your head, has there been any talk of like -- when does this multi-page app transition API come out of -- like go stable?
MAXI: I'm not sure. I haven't heard any dates. I know they're working on it. I think they released the first version in, I want to say, November of last year. And they've been working on it for, you know, over six months. This is like behind a feature flag. So I want to say it's going to be pretty soon because the SPA version didn't take that long to become stable.
JASON: Sure.
MAXI: So this might be hitting browsers soon.
JASON: So as we're kind of running out of time here, just to recap, the view transition API that we're using to do this, which is the same page we are modifying something based on hidden visible classes, this is available today in all Chromium browsers? Or is it also Firefox and Web Kit?
MAXI: Only Chromium browsers for now. I know Safari and Firefox have been interested, but I haven't heard anything about implementing it.
JASON: Okay. So with this kind of browser detection fallback, you can double check that the thing is available. Then add it progressively. So, nice progressive enhancement there. It'll work in all Chromium browsers today. So Arc, et cetera. If you want to use the multi-page view transitions, it currently only works in Chrome Canary behind a feature flag. But if the precedent of how long it took them to get the single-page app transitions holds, then we're probably six-ish months away from seeing the multi-page app land.
MAXI: Yeah, maybe. I hope so. I hope that's -- I don't want to speak for the Chrome team.
JASON: You know, there are very few things I get to play with on the web where I just get that giddy feeling of, oh, my god, this is so exciting. One of the places I continue to get that feeling is with these new browser APIs. I'm so happy to see how far the browser has come, how much power we have without having to install third-party libraries, without having to maintain custom JavaScript. Like, this is some incredible stuff. So as we're kind of coming to the end, is there anything you want to make sure people see, any resources, any demos that you want to show off before we run out of time?
MAXI: Yeah, so resources, there is a blog post on Chrome. I'll share the link. It's the same blog post we shared before, which has all the information you need to get started with this. So I will share the link. So there is examples of how to do pretty much everything you can do with this API. There is also one thing we didn't talk about, which is handling when you transition between elements that have different aspect ratios. So there are some tricks you can do with CSS to make that a smooth transition.
JASON: Nice.
MAXI: Yeah. And then, yeah, if you check my Twitter account, I share demos from time to time. Also follow Adam on Twitter. They work on this API all the time. Make sure to check them out.
JASON: Let me hide a couple things here so I can actually pull up these windows because I'm not logged in on Twitter, and apparently you can't look at people's accounts without being logged in anymore. You mentioned Argyle. And who was the other account?
MAXI: Bramus. They are the ones working on this API. So yeah, make sure -- they share demos as well and share resources.
JASON: Yeah, so much exciting stuff happening in this space. And let me pull up your Twitter one more time so that as I'm talking about you -- yeah, all right. So this is something that I think is immediately useful. I'm going to start using this, like, today. I want to start using this right now. And for anybody who's interested, the SPA version is available now in Chromium browsers with a nice progressive enhancement path. Is there anything else you want to say or show off before I do the teardown?
MAXI: No, check out the API. Give the team feedback as well. They always look for feedback. I was mentioning one of the limitations of the API, and they're working on that. So it's going to just get better over the next few months or years. So your feedback is very important. The team is looking for feedback. They want to build a robust feature. So if you play with it, make sure you give them a shout.
JASON: Awesome. All right. Well, with that, I think we're going to call this one a success. We're going to find somebody to raid. And we will see you all next time. Maxi, thank you so much for taking time with us today.
MAXI: Yeah, thank you for having me. This was fun.
JASON: Take care, y'all.
MAXI: Bye, folks.
Learn With Jason is made possible by our sponsors: