 Am I loud? Yes I'm loud. Good. Am I? Yes I am. How are you doing? How are you doing? Not bad. At the back, how are you doing? At the front. At the front? Right. I'd love the idea that you can figure out where broadly speaking people are from from the way they cheer. I came out the Tower Hill station this morning and yesterday. And it reminded me, the last time I was at Tower Hill was to go to the Tower of London with Paul Irish. And we went on the tour- Who by the way is not Irish? It's shocking. And we were there and the Yeoman went, are you ready for the tour? And everybody went, whee! In that British style, apart from Paul Irish, it went, whew! Now I enjoyed it because the Yeoman just went, there's an American in the crowd. And I was like, okay, but I think he's allowed. I think he paid, it's fine. Anyway, that's not what we're here for. So overnight we run a show called Supercharged on youtube.com slash Chrome developers. Well done, well said. Hashtag branding. And what we normally do is we normally spend some time live coding on a live stream, some UI elements. And we thought we'd do it live, live for you today. That kind of idea of doing live coding. If you've ever watched the show before, we usually have the YouTube live chat and I read it and I distract them with a question. It really does. Today, we're gonna use the Polymer Select channel. So for you people in the room, the people watching the stream at home or at work, wherever, come into the Supercharged channel and ask your questions throughout the live stream here. I'm gonna be watching the chat and reading it provided I can keep up. Yeah. And I'm gonna try to weave in all the questions that you have and we'll try to answer them if we know. Yeah, so the idea is I'm gonna build a UI element and normally they're quite practical like side nubs and stuff that you, no, not today. It's gonna be overblown and ridiculous. Or as ridiculous as I can bring myself to make it. We call it showbiz. We do. Showbiz, right, you can see what's on my screen. So I may as well get started with code. Yay. Because we got the question all the time, this is VS code. Yeah, there we go. Snippets on your franches of past Typer. I'm a bad Typer Polymer Summit. Give me a title. If anybody wants to do like account how many typos he does, I would be curious to see that. Don't do that, don't do that, right. REL equals import. Because it is the Polymer Summit. I thought I'd do web components. I'm not gonna do Polymer. I'm just gonna go, I'm gonna use the platform. That's what I'm gonna do. I'm gonna go straight in and see what happens. I've never heard that before today. I know, weird, isn't it? You used the platform. Hashtag branding. Damn. Okay, href equals, and now I'm gonna make a, here's what I thought. Let's make something where, like imagine a disk and it's got like a value on the front, like one, two, three, four, whatever. And you click it and it flips over in 3D. Why not? And on the back you can choose like one, two, three, four and then it flips back over and show you what the current value is. Sounds ridiculous enough? Good, let's do it. It's like a tab. So I'm gonna call it, but in 3D. I'm gonna call it flip switch.html. So before in the show, we have used custom elements, but only v0. So I'm gonna be new to this. I actually like, I plugged my ears. I didn't watch any of the talks. So I didn't know how v1 works. I don't know how anything works. So I will be educated by this and I'll probably ask questions even you know the answers to. Cool. Right, so flip switch.js. How's everybody doing in the chat? We're actually suddenly we have a search of people coming in, which is great. Awesome. Right, so what I've got is I've got, let me see if I can explain what I'm actually doing. I'm going to- My first question would be, you're in a separate file already, which is just like no doc type, no- I know right, because it's an HTML import. So I've got an HTML import with, which I've called async because I'm being good about that. And I've got my custom elements. So my theory was I'll use all the web component primitives that make sense here. So I've got an HTML import, which I'm going to use basically, I'm going to have a template, which I figure is going to be stamped in to the shadow DOM of the thing that I'm making. And then I have the JavaScript itself. So let's make that, why not? Flip switch.js. And friends don't let friends write out custom elements by hand. They have snippets. Because if I was left alone to write things like the constructor, I would forget to call it super. And that would break everything. I don't know why it breaks everything. But if you don't, the browsers all go, yeah. But if you put in super, it's like, sure. Yeah, that's fine. It's an HTML element now. So look for me, this is already new, because previously you had and the constructor would never be called, but instead you would have the created callback. Correct. And now in v1, we apparently moved to the actual cluster, which I like. I like that you bumped it to v2 there, dude. Yes, oh, whoa, whoa, don't do that, vs code, come back. Right, well, let's do, by the way, this is going to be at me. See, class, it doesn't like it. It's like ESLint, it's like, no. So let's make it okay with it. ESLint nv. ES6. Ta-da. And now it's fine. I didn't know you were, you didn't know. It didn't know, it's fine. Right, let's make sure this is actually working console.log. Flip switch. Oh, there's my server. Come on. Yes. That's a start. So we actually have, it's- What did we just do? It's figured out that, see now every time I switch is gonna be, right, there we go. It's figured out that I actually have a flip switch in my page and it's called the constructor and now it's spat out. Flip switch. We're gonna have to go faster than this if we actually wanna make some progress. So I should get on with it. Right, so let me make sure that this is actually gonna work. Let's do some styles in here. And I'm gonna tell the host that I want it to be background, red, display, block, with 200 pixels height. Don't be marking my typing because it's awful. With height, 200%, 200 pixels. That seems good. Units are hard. I know. They are for me. All right, okay. So now here's the thing. What we're gonna do is we're gonna try and snap it into the shadow DOM. So I need to know, because it's in an import, I have to know which import it is. So doc equals, that's the main document, current script. Yeah, it'll be current script. Who's running? Which is this? And then I say, who's the owner of that doc? There we go. I own a document for that. And he goes, yeah, this one. So now I can say- Wait, so document and only document can be different? Yeah, document is the main document. The owner document is the owner of the current script, which is the doc script. So I can now say doc.query selector, like so. And I can ask for my FS temple, which is going to need the hash on the front because it's an ID. And then I can do, oh yeah, this dot attach shadow. Sounds so good, every time I say it. Mode open. Open. I'm gonna leave it be open. So what is it? Yeah, that's what it means. Basically, I think it's, are you allowed to access the shadow root from outside or not? If I'm wrong, somebody's gonna correct us, probably on the chat. But I'm pretty sure if it's closed, it means that you can't. So only people who actually have the reference returned by this can use the shadow root if it's not open. Sounds about right. Okay, that would make sense. Yeah, and we're gonna append child. And we'll say temple dot or content, because you have to do that on the template, dot clone nude deep is true. Who, look at that. Do you see that? It was like, all right. This code was like deep. Yes, do that. Right. Yes, I've got a red block. It's gotta get more showbiz than this. And we're done. Yeah, and we're done. See you later. Right, in the main page, I'm gonna, let's do some myth busting. Ready? Style. You know that? Apple. Shut up. All right, HTML buddy. What do it? Ooh, width 100%. I'm just gonna basically make this thing take up 100%. Why not? And let's see width height 100%. Let's see margin zero padding zero. Yeah. And here's the thing. When somebody tells you that you can't vertically align in CSS, they're lying to you because with two lines, display flex, flex and align items. Center. Center. Even I knew that. There we go. Vertically aligned. And also justify, justify, just see. Told you. And now it's actually in the middle. It's in the middle. Everything. I love it. It's so good. Flexbox. So good. I remember back then when you had to do like a zero pixel, zero by zero pixel object and then do relative 50% and whatnot. Shout out to Spacer GIFs. Spacer GIFs. Those are good times. Okay. I'm glad we had this chat. It's feeling quite emotional. Right. So that's in the middle. And what I'll do is I will now start adding some stuff. Now, if it's going to do that thing where it's going to actually going to flip forward, it's something which has got a front and a back. So I'm going to make a container for those because I've got a feeling I'm going to need one. Yes. I'm going to need one because I'm going to put things like perspective on. So div class equals front. I will say front. Cisla. Does what it says on the tin. And we'll need one for the back as well. Back. Back. Back. How's the chat doing? So I'm assuming this is like the front card, the front side and the back side, eventually of the thing that you mentioned will be flipping. That's the one. That's the one. So we'll say. We've done something similar before with a 3D card flip. Yep. Where we, I guess, talk more about the shadow than the actual card flip in the end. That's correct. Because we had to do it efficiently to get the 60 FPS. But we had the same setup. We had like a front and a back and basically one thing was becoming visible and the other one becoming invisible when things are flipping over. Front. So if you don't know that, watch that episode. They're all on YouTube, on demand. Maybe good to fall asleep with or something. Yeah. The sound of our voices. Probably not. No. Right. So I've positioned them absolutely and told them to be with 100% top left zero and they've decided to break out of the containing element because their parent, which is container, is statically positioned. So we'll have to say position. We'll do relative. And that will bring them back in. That looks pretty. Yeah, I know. It looks amazing. Give me time. Give it time. I've got a lot of faith in where we're going. Right, they're still not 100%. Wow, you need to be with 100%. That's why. So the container needs to be 100% of the thing. There you see. Now we're in the middle. But they look ridiculous. So let's fix that. And what we'll do is we'll set background. Ooh, ooh, ooh. Here's an idea. Let's do color. Yay. Custom properties. One, a three, two. This'll be a greeny color. Of course you know that. Oh, by the way, just because before anybody calls us that. Seriously, yeah, come on, a three's more than two, six and one. All right, fine, fine, fine. By the way, I don't know what we're doing today. But Paul, to be fair, we wanted to say that he did rehearse this because we are strictly time boxed this time and don't have this dream where we can go on as long as we want to. So this has been rehearsed by him, not by me. So I don't know. Thanks for telling them that I didn't just figure out that I was screamed by myself. OK, so, right, we don't need the red anymore because we know that this is working. OK, so we've got the front and the back, and the back is sitting on top of the front, which isn't kind of really what we want. We actually want a front and a back face, right? So we want to rotate the back face by 180 degrees. So let's put the back, like front side. And we've got a front. Look, we've got a front and a back, right? So the front is facing us, but the back is also facing us, which is ridiculous. That's not real life. So the back has the face away from you, right? OK, cool. So we're going to do a transform, and we're going to rotate y 180 degrees, like so. And now the back is, it is back, but because the way 3D transforms work, they show you the back face of the thing by default. It's back face visible. You mean back face visibility? Visible. So both of these will serve them. Just yes, that's right. Sorry, back face visibility. I can't type today. And hidden. OK, that will make the back is still there, but it's now actually hidden away, which is ridiculous. If you've ever done any open GL or web GL work, you will have encountered similar behavior there. Back face calling, indeed. Exactly. Background. So if you flip something around, sometimes it's visible, sometimes it's not depending on how you configure your engine. OK, so let's do the bit where it actually flips over, because that's more fun. So in order to do that, what I'm going to do is on the host, I'm going to set a perspective value, which you always set in pixels, perspective 500 pixels. And what I'm going to do is I'm going to push the container back 250 pixels, and it's going to become this pivot for us. And then we're going to push the front in the back another 250, and so that when they flip forward, they're going to be at zero. Does that make sense? I guess. Yes. Let's find out. Let's do translate, transform, transform. We don't have theory corner here. We could just use a good flip or just draw. We do actually have a theory corner. Or what do you call it? Theory echo. Theory echo. I see. And that's the German. It's a little bit more edgy. Tell them what the German is for CSS. Kaskadieren des Stilisierungsvorlagen. Oh, it's so good. Oh, it's so good. There's going to be a pop quiz later, so memorize this. It's going to be awkward if you can't say it. I can't say it. Right. So I've pushed it back into in the space, or Z space, because we're in the UK. So does the Z go into the monitor or out of the monitor? There's negative Z values go in. Oh, so the axis goes out. I can never memorize it. Well, here we are. So at the moment, it's basically what was it? It was like 133 pixels. And the reason is, if you want to work out how much something is going to get scaled down or up by, it is always the perspective value divided by perspective minus the distance, which was minus 250. This is literally in the spec, but it's in like a node. I don't know why I know. By the way, if you would like to know, this is the math you're always looking for. So now that's why it's like 133, because that's like 66% of the 200, right? So that's why it's that size. So what we'll do, I'll tell you what we'll do. We'll push the front and the back like so. So we'll have 80 people in the chat room right now, which is good. Could be more. Are they asking anything? Like Rob is almost answering anything. But yeah, they are searching. Go, Bob Dodd. Shout out to Bob. It means you're, I don't want to say you're redundant. I'm glad you're here with me. I'm in the chat. Shout out to Serma. Yeah. My safety, Serma, you see when I go wrong. Right, I put the, you might not have seen actually, I put in the extra transform, but it didn't actually do anything like so. It's still at 133, whereas you'd expect it to have gone another 250 pixels back. Well, that's not going to happen. The reason it's not going to happen is this. The flip switch has a perspective value of 500. The container is pushed back by 250 pixels. But then we push something else, another 250 pixels. But the container's in the way between the item with perspective on it. So it goes, lol, no. What we have to do is we actually have to ask the container to preserve the parent's perspective and pass it down to the children, which we can do by doing transform style preserve 3D. And now it'll get smaller. OK, so that now it's basically said, OK, I'll take the parent's perspective and pass it to the children. So now that's all good, isn't it? How are we doing for time? We're doing all right. We're about 18 minutes. Easy. Yep. OK, let's. So we were doing the thing where the container, what we'll do is we'll flip it. Flip it. So one theme in the questions is right now, like, is it going to work in Firefox? Is it going to work in Safari? With polyfills, yeah. With polyfills, it probably would work. Right now we're just, this is, as always, we always say this in our show every time. This is not production ready code. No. We're just, we're doing this on stage. This is probably going to be horrible. So don't just copy it and paste it out, but this is about the technique. And it's going to work in Chrome right away because we're developing Chrome. And you probably can add some polyfills to make it work everywhere else. This stuff, if you didn't use the HTML imports, if you didn't use the shadowed arm and all that, you could make this completely work as far back as whichever browsers were the last to get 3D transforms. I guess it should be fine in the IE10 even, maybe. Yeah, it should be. I think I don't know. If you want to cry, try to make this work in IE10. It's your homework. Right, so basically what I've got is I've got the container. And when the container gets a class of flipped, it's going to rotate x 180 degrees because it's in the pivot, so we should see our cards basically go over. Now, what we have to do is go back here and we're going to have to ask for the container. This.container equals the root.querySelector. And what was it called? It was called container. That's why I can't. People are asking you to zoom in a bit. Zoom in like this bit? Why not? Yeah, OK, fine. Are we also on the website? Maybe. Hang on. Although, maybe not. This. Well, oh, so here we go. Add event listeners. Add event listeners. So I like to do this. The pull trick. I know I just know I'm not going to do that today. I'm just going to do this. I'm just fine. But I'm basically document.addEventListener. When you click, I'm going to basically do it this way just so we can check that everything's working. This.flip. I'm going to flip things over like so. So I need a function called flip. So you're also giving the element an actual API. I am giving the element an API. And I can just say this.container.classList.toggle flipped, which is going to do nothing. Oh, no, it is. I'm an idiot. You don't have the dot in there. You only have it in query selector. There you go. Right, zoom that in a little bit. For now. Now, the back is upside down, which looks ridiculous. And it's not animating, which is also ridiculous. So let's fix both of those. Transition on transform. And we'll do 0.8 seconds. And I do honestly think this is one of the nicer easing out curves, 0.6, 0.31. Oh, that's a new one, though. I know. I don't normally use that, do I? Usually you have 0, 0. Now, you see that? See that's broken in it. That's really broken. Let's fix that as well. Do you know why? No, I don't. I do. Because I've seen this bug before. The front and back, I've got a transform there. But then I override the back with its transform rotate, rotate y. So I need to put that in there so that it remains. So we have a question. Hang on, hang on. There you go. See how that's woohoo. The only downside is that's actually upside down. Because I suppose if I did that with my hand, my hand ends upside down. It is physically correct in that sense. Yeah, so let's rotate it in Z. Rotate it a bit like that through. And then whoop, like that, just like that. So 180 degrees. And yeah, look at that show biz. Right, so what's the question? You added event listeners in unconnected or in something like that? Yeah, so I'd normally have a. So if we removed the element from the DOM and moved it somewhere that's unedited, you would have multiple event listeners, right? I would normally, in a disconnected callback, I would remove event listeners for time. Production ready code. There we are. I'll put that in for you. Right, where were we? Right, so the thing is, when you click on this, that's kind of OK. But let's actually add some buttons. Because I did say that we were going to have some buttons, which we'll do in here. So we'll have a button. Speaking of, now that you have basically had experience with both V0 and V1 of custom elements and maybe even Shadow DOM, preferences, differences, doesn't really matter. No, I've rose by any of the name. I think it's still awesome. I really like the fact that it now uses the construction instead of created callback. I like that, too. And I really, I mean, this is just attached and detached callback by another name. An attribute change callback is still attribute change callback. So for me, mostly, this hasn't really changed. This one caught me out that if you're going to change an attribute, you have to declare as a static. Which I guess is a performance optimization. Yeah, these are the only ones I care about. And it's called custom elements define and not register element. Don't do it and not register element. It was before, but mostly, you know, it's fine. Well, it's just syntactic changes. It seems like it's really quite fine. Right, so we had buttons on the front, right? Yeah, it's got really attractive looking 1 and 1, 2, 3, 4. OK, let's style up the front button. Let's do that. It's, oh dear. Right, front button. Right, width. See how much I can do here. 100%. Height, 100%. Oh, let's see. It seems repetitive. I know, right? Border radius, 50%. Because we're going to want that. Outline none, because I'm going to do a hover state in itself. I'm going to do font size 60 pixels. Oh, background none, because it's that gray at the moment. Border none. Don't want any of that. Yeah, OK, color. La, la, la. Make a white color. There we go. Let's do a, there we go. Someone is suggesting using mix-in for the sizes, which I guess would make sense, but they're not vanilla. You know what? Yeah, absolutely, it's in production. You totally use some tooling here, wouldn't you? Like, I'm obsessed with focus. Especially every single thing we are using, you can see on screen, more or less. The only thing you can see is the Python web server. And that's about it. So here's what I'm doing. Using a box shadow, which is going to need to be inset. With, like, zero on the x, y, zero on the blur, these, x, y, and blur, all zero, and then a 10 pixel spread, which will bring it in 10 pixels, which is kind of cool. And then we'll do a 0, 0, 0, 0.4. There you go. Why not? And then we get that. Right, that's fine. Now on the back. Ship it. Ship it, it's done. Would you stop it? Trying to save time here. I know, but they're expecting it. I was worth a content. Back. Back. We'll do the back buttons. Oh, I get to do something I quite enjoy on this, I think. 25%. Because there's four of them, so I'll make them smaller. I'll make that a little bit smaller. Someone suggested that we should use a transition box shadow. And does that, at least? No. No, no, no, no, no, no, no, no, no. Bad. No. No. If you don't. No. Yeah. That is what the card flip episode was mostly about. Yeah, you don't animate box shadow. You don't do that. Never do it. Because it will trigger paint on every frame of the animation. And so far, you've seen me stick to transforms. And you'll see me stick to transforms and opacity for that reason. They are the only. Always. The only properties that today will animate in an accelerated version. Which basically means that we create layers for them on the GPU. And then we can move them around with the transform. Or we can fade them in and out. And that's really, really fast. And that tends to be fast in all browsers. If you're painting on every frame, it's a gamble. You might get away with it. And a mobile, you mostly will not. You probably won't. And I think you can with a lot of slight, a bit of slight hand. It depends on the thing. You can get away with it. But usually transform, opacity, nothing else. If I was doing this differently, I'd probably use a before or an after. And I'd probably do that box shadow on it. And then I'd just fade it in and out. Or I'd scale it or something like that. There's ways to do it which don't involve paint mostly. Right. Where was I? I was doing the background for this. Wasn't I? It's like an inverse color thing going on. So on that side, it's like that. And then 1, 2, 3, 4. OK. Now they look ridiculous where they are, don't they? So let's put them in a nicer place. Position absolute top. 50%. This is one of my favorite little things as well. Is when you do that, and you've got them, they are actually in the middle. But it's the top left corner that's in the middle. Yeah, but I'd like to just middle. Middle would be good. You can just do a translate, transform, translate. Minus 50%. Because the fun fact here is that in this case, your translation works on users for the percentages. The dimensions of the elements are being used and not the parent. So handy. So handy. So good. Right. So now let's see. We've got backbones. But let's position them in a little more. Right. So we've got a number of types of type one. I'm just going to assume we've only ever got four boxes because it's prototype code. So one, two, three, three, and four. Right. So button one, button one. There we are. It's going to be staying at minus 50, and we'll bump it up by another 100%. There we are. Two is going to go out to the sides. That'll be a plus 50 with a minus 50. Well, I want one, two, three, four. Like a gamepad thing. Yeah. Are we going to use the gamepad API? No, shut up. Let's find out if that works. I mean, normally you just... Sounds about right. Let's find out. One, two, three, four. Yeah. Okay, cool. So we've got buttons. But I think because these are... They've got to transform here as their default, and then they've got to transform here. We could take advantage of the fact that their parent gets flipped. So we could just do a nice little animation for them here by doing this, and then let's do... Oh, I've already got it. Don't repeat yourself, Paul. Grab that. Let's make the button animate. So... Oh. Now, you probably didn't see that. Let's slow it down. Slow it down. Animations. Great feature of DevTools, by the way. Slow it down. Slow-mo. Oh, you can see it. Yes. Yeah, there's a little spread. You could put a delay or something, or like a curve or... Thanks for sending my thunder. Transition delay. I know some stuff. You do know loads of stuff. 0.1, 0.15. Let's delay the animation. We'll do it, you know. You know, I think that a bit of delay... There we go. So you see how they spread out at the end? Is it... And then we... Yeah, that's good. Right. Let's do it so that they actually change the value now. When you actually click on one of those buttons, let's actually have it update the value on the front. So we can do that with... Ooh, let's think about this. Let's do a setter and a getter. Set value. Oh, I know you're going fancy. I know, right? So good. This dot value... Whoo! Equals value. Fair enough. Except that you've got to make that underscore pull. Get value. Return this dot value. And what we can do is we can say this dot front eu.query select. This is bad. But I should really be caching this instead of asking for it every time. Dot text content equals... And then again... Value. And then we need to know what front is because we don't currently have it. Equals this dot root dot query select. Front. Front... Oh, yeah. Same for the back. Yeah? Because we're probably... We're going to need the back... So just saving the references to these two elements. We know we're going to need it. Yeah. Right. So what happens is we basically got the front. It's fine. And so what we need to do is we need to say this dot front. When you click anywhere on the front, because the button takes up the whole thing, we'll just flip the thing over. Yeah. This... But we'll delegate to the back. In case we do some time, decide that we want more than one button. And we'll say... When you click... And now you're giving me ideas. I know, right? What we'll do is... Well, there's going to be a problem with this. We'll do flip. But we'll do this dot... Value equals whatever the target was. I'll do it. So we basically... You could at least use data set or something. All right. So if we click on the four... There you go. It's actually setting the value. But the problem is if we click on the back... Whoops. Working as intended. Awkward. Good news is there are the most ridiculously named properties on an event. There's the current target and the target. If you don't know, that's because events bubble. It's just I don't care. Target and current target. Are you the current target? No, I'm the target. How's that different? Don't know. Ask the current target. If the event target is the same as the event dot current target, which basically means... The thing that you clicked on... The target... Is the current target, which is the thing that was actually... So have the event target... Basically saying have you... Have you clicked on that? If you had not bubbled. No. Yeah. Yeah. Then we're just going to return. Right? So this is like if this is the back. Right? So hopefully that will work. So it doesn't do that, but now it does do that. That's that problem solved. Right. So that's all working. I had an idea. Let's make it a little more showbiz. We had a question, by the way. Are we doing DOM operations in the constructor right now? Because that is apparently not recommended. Other than attaching the shadow. Are we doing query selector? Sure. I mean it works, right? I'm going to walk you to some... Matt is not going to be there. Hi, Matt. Yeah. Come on, do the thing that... Okay, Matt. I'm going to undermine everything you say. Sorry about that. Okay. So let's see. Right. Wait, wait, wait. Oh, yes. I'm going to add a ripple. A ripple. Ripple. Everybody likes a ripple. Dave, class equals ripple. Now, let's add that in. In case you didn't know, by the way, all of our episodes, the code that comes out of those, is on GitHub. This will also be on GitHub later on. And the Google Chrome org on GitHub called UI element samples, if I'm not mistaken. We probably have a link on screen, hopefully. There's dashes. UI dash element. True. You'll find it. We'll also have it in the description and the video on demand later on. So go there if you want to play it on with it yourself and make it work in IE 10 or whatever. Close your vote. Yeah. Absolute left. 50%. Top 50%. This sounds really familiar, doesn't it? Transform. Translate. Transhalte. Trans 50%. Minus 50%. This is going to position the ripple. Whoa. You didn't see that. It's fine. It's fine. I expected that because I didn't have the border radius. Now we've got a ripple. And that looks, I know, just bear with me. It's actually quite a nice aesthetic, I have to say. Right. Don't get distracted, Paul. Ripple.expanded. Right? Because we want to expand and contract. So scale down to zero. I'm going to scale it down to zero. And then I'm going to scale it up to one when we call this class. Now. It's going to go like. Yeah. But we will want to transition on transform. So let's make sure we've got that in place because otherwise it'll just pop like that. The official sound of popping. We'll make it a little faster than the flip because ripples, it's got quite a long way to go. So I kind of like it when it just gets on with it. So we'll make it a touch faster than the actual flipping over animation. So we've actually got to tell the, you know, we've got to toggle that class. Well, it's good because we've kind of got that stuff already in place. Ripple. Ripple. It's actually an interesting question. We haven't seen a single world change in your code so far. Why is that? Give it a moment. Yeah. Class list.toggle. Expanded. Expanded. We also actually haven't proven that it doesn't paint. Right. But that will paint. Let me show you that it will paint. What? Let's choose a different color. Oh, a green is like, DevTools uses green to indicate painting. So that's kind of not. Whoops. Let's do Rebecca purple. See, I didn't even have to say it. I was just asking for this color in the chat. Well, lovely color. Anyway, look, there you go. So now we do paint flashing. Every time Chrome paints, it will put a green flash on the screen like that. See? Because you're hovering, the border has to be added and therefore paint is happening. It needs to be painted like literally. Now during the animation, because it's an animation on transforms, Chrome goes, ah, got this. I'm going to give it its own layer, which is a bit like in an art package, right, where you make your own kind of layer and it has to repaint that bit. So you'll see that it goes, and then at the end you see that green box around the ripple. We don't want that. It's basically if the flatten of all the layers back down to one single image, so to speak, on the GPU. So what we can do is we can say to Chrome, and it also works in Safari and Firefox, we can say, listen, that ripple, like if you're seeing the ripple, it should have its own layer. So we just do will change, which is the way to do this. You can use the... And there we go. We've got a will change. Anybody done translate Z zero before in their histories, have ever? Yeah, everybody uses will change. Okay. Okay. But if you haven't, and you've seen translate Z zero or translate Z zero, that's exactly what it's doing. Visually in NOAA, but it was a hack for Safari. Back in the day, and then it was every other browser pretty much since was like, oh, you're putting a 3D transform. That means it should have its own compositor layer. I should do that now. Well, will change is the kind of the standardized version. And so at the end of this, see how we don't see that paint anymore. And if we actually show layer borders, Chrome will show us anything that it thinks has got its own layer. That's actually visible. Yeah, you can see that. And that's really good for us here. So this one will have it because of the fact that it's got the perspective on it. So it knows there's a 3D transform here, but the ripple gets one because of the fact that we've told it it needs one. There is a list of properties that basically force our advice for the browser to use their own layer. Yeah. I think was in the spec of CS. I don't remember. Yeah. I might link to it in the chat. There's like a list of transfer, a list of CSS properties that force an element to its own layer. And from there on in, you can do accelerated animations. Okay, I've set the size of the ripple to one pixel, which seems inadvisable because you won't ever see it. However, the thing is, it wants to be the size of the screen, right? We want it to kind of take over, do like a full takeover, which means it's like... Do we? We do. Okay. And these change size, right? Windows and that. So we need a resize handler to kind of figure out, okay, how big does this ripple need to be? Like the radius of this ripple. So I set it to one pixel because I know I'm going to have to figure this out in JavaScript. So what I'll do is I'm going to make an on resize, resize like so, and we'll do window.add event listener, resize this dot on... Do you know what? That's going to fail, but I'll show you why that's going to fail in a little bit. Right, const, middle x. Now, I'm going to make the assumption that this is always in the middle of the screen. If we have time, there might be a more generalized version that I can show you. Middle of the screen is the window dot inner width times by 0.5, and the y value is the inner height also times by 0.5. Something you could use here if we were really bleeding edge. We could be using the new resize observer. Wow, that is... That is a thing I... Coincidentally, I just wrote an article about it. I'm posting it in the chat right now. Go read it, maybe. It's basically an observer that only notifies you when a resize happens. Not only on the window, but you can do it on elements. So it's basically the event for elements, and it's amazing. I encourage you to do that. But right now it's only in canary behind the flag. That's a little bit keen for me today. Yeah. So we need the Pythagorean distance, don't we? We need the... We're doing math now. We are from there, from the middle up to the corner. Whichever corner is nearest was, because it's in the middle, it's always the, you know, pick one. And so the radius will be the square root of mid x times by mid x, mid x, plus mid y times mid y. And then we can say this dot ripple dot style dot width equals template tree radius times two pixels. Ooh, put a space in, Paul. There's a good lad. Height, also the same thing. That didn't work. Great. Hate it when this doesn't work. Okay, fine. Why didn't you work? Oh, it's because I didn't actually call it. Awkward. Right. This dot on resize, we'll just do it here for now. Yay! And also when I resize it, it breaks. And the reason it breaks is if we were to do console dot log this. Ooh. Ah. And we say, I was wondering if it's full. So the first one, yeah, the first one says, oh, yeah, this refers to the flip switch. But because of the second one is window dot add event list and then resize it goes, this is the window which is no use to me. So we are in the age of years 2015, but even then sometimes a bind is still necessary. I know. I'm still going to bind this. Oh, look at this. Paul Lewis way or the normal way? Mine. Let me explain why I'm doing this. That looks horrible. This is basically a feature in every episode. I'm very proud of it. I'm not proud of it. It's just necessary. It's going to be in the pop quiz. Okay, fine. Right, the reason I do it like this is because I want two things. I want to be able to refer to it by name because if I do my tidy up, which I promise when I do push this to GitHub it will have the disconnect callback stuff filled out. I might even move that to this stuff here anyway. But the thing is I want to be able to refer to it by name. So I want to be able to say this dot on resize with my add event listener and my remove event listener. That's one. The second thing is whenever I call that function I want this to be always referring to the instance. I do not want it to refer to the window or anything else. So what I do is I take a copy from the prototype because it's a class. That's exactly where this currently lives on the prototype. And I'm going to take a copy. I'm going to bind it to this and then I'm going to shove it as an actual property on the instance itself. So that means you're overwriting it. Basically, yeah. So that then always means that no matter what it will always refer to the flip switch. There is actually in 2017, I think, there's a proposal for a double colon operator. Of course there is. That would be this colon colon on resize which would achieve the same effect. But it's not there yet, sadly. It's jittering because I'm plugged into a monitor. This, by the way, it runs great when you dump. You'll see it when you play with it. It's great. Very cool hearing. Yeah, I know. Okay. Last thing. I feel like we should have shadows. The audience does not seem to care. Oh, they don't care. I'm doing shadows, okay? Thank you. Well done. I like you. I like you very much. Okay, let's do a shadow. Shout out to shadows. Shout out to shadows. Shadow. Right. Two pixel one. And then, yeah, stick with me. Shadow, two pixels. Okay. It's going to be width. This sounds really familiar. Height, 100%. Background. This is going to be a black shadow to begin with. And let's see position. Absolute. Top zero. Left zero. Border radius. 50%. What a great shadow. I know, right? It's amazing. It's actually like a record. I know. And that's not the only thing I do. I do a great Billy as well, if you'd like. There we go. I don't mind. I could do the whole. If you ask a question, I might respond in my best Billy. I don't mind, whatever. Anyway, going back to this, which was not. Code, Paul. Code. Focus. Now, the thing is that you remember the container got pushed back 250 pixels. And the thing got pushed back another 250 pixels. And they were half size, which we can confirm is 500 pixels minus. Sorry, over 500 minus. And then the distance they moved, which is another 500, which is 0.5. So they are half scaled at the moment. Double negative is too much. I know, but that's true. It's half size. So we could put the shadow inside the container as well. But then when that flips over, the shadow is going to go a little bit wonky. So let's not bother with that. What we'll do instead is we'll cheat. And we'll do a transform and we'll scale it down by 0.5. Now it's hidden, but it is there, right? It's there. But let's translate it down a little bit. Translate why? Two pixels. Yeah, just a couple. So it's peeking out the bottom there. It is. But here's what we can do as well. We can also make it look blurry by adding a box shadow. But if you get it wrong, let me see. Box shadow 0, 0, 0. Now it's half size. So my two pixel blurry shadow, it's going to have to be four pixels. And we'll make that black as well. Now, yeah. No, man. Oh, you can't see that. You can't see that. Change the color again? I need to blur it. That's why. I'm an idiot. There you are. All right. Let me get rid of this. There we go. Oh, it wasn't one of many numbers. OK. Right. Yeah. Interesting question. Why not filter blur? I've gone to this problem before, I think. Yes. Filter blur. Why wouldn't you use that? Because it's a post-processing effect, which means that when you, when the frame gets shipped to the GPU, the GPU goes, do I need to blur this? Yes, I do. And if the animation is, if it's changed at all, if the pixels have changed at all, it will go, oh, I need to blur this. And that will happen on every frame. And blurring on every frame is incredibly expensive. So it's like a post-processing effect that you don't want to be running on every frame. If you have some static content that you don't animate. And the deceptive thing is actually that paint flashing will not show up. No, it won't. Because it's not done in the tabs rendering pipeline, but outside of it in the post-processing pipeline. So it's really deceptive that you think you have done well into the performance, and actually your frames get really slow. OK. Back to the shadow. If you can see there, there is a shadow, but you can see that it's got the hard edge of the circle, and then the shadow kicks in. If you add a bit of a spread onto this, it kind of, see how it's now like a blurry shadow? You could zoom in with control and mouse wheel, right? I don't think I can. No, I don't. Because I don't think that the things which are for the thing with the thing. Again, very articulate. Let's put that back where it was. Right? Looking good. OK. What we'll do is we'll add another class to this, where it goes like flipped. Yeah. And we will, you know how those, the disk, let me just zoom it out a little bit more. The disk goes from like there, and it's like big, and it's like 200 by 200 again. Well, since this was 200 by 200 when it wasn't scaled, we can just get rid of that downscaling. So now it'll be like the right size. So now it goes back, because if you don't define it, it goes back to scale one implicitly, and that means it will zoom, it gets bigger, I guess. Exactly. And let's transition on transform again, so that it moves nicely. So let's do that. And we will have to add that into the JavaScript, to make sure that it actually gets told what to do. So shadow, two pixels. How's everybody doing on the chat? I've been forwarding a few questions. We have 115 people by now in the chat, which is nice. Can we get to 200? I don't know. Me neither. If only there were like 200 people in the room with us. We have enough people actually in the room, which is scary enough. No. They're watching. You type. There you go. OK. I'm kind of rubbish, because the animation is... I don't know. The thing is it should flip over as well. Let me show it again. Rotate X. Let me just put that in. There we go. Slow it down. Yeah. I think it's doing a double flip, isn't it? No. No, it's not. It's not. Now, it's obviously a lot darker than we need a shadow to be. So let's fix that by dropping the opacity to zero. Opacity from 0.3. 0.2. 0.3. Magic numbers. You're good at them. I am. Right. Now, the thing I know about shadows... I was about to say, don't they get lighter when you... They do, and they also get blurrier. Now, I don't want to change box shadow, like I said, but I know that we could fake it. Well, you make it. For Monica. Yeah. Meenika. I'm calling her now, because she was mean to me yesterday. Because she ruined her day. Yeah, well, she ruined my day yesterday by calling me mean. Meenika. There you go. Hashtag revenge. Okay. Let's add another shadow, which will be exactly the same as the two-pixel shadow, but we'll make it blurrier. Error. Error. And so it'll be exactly the same as the two-pixel shadow, but we will say that it's box shadow. Again, we'll have to double the numbers because it's going to be a half-size, 24 pixels. I'm going to give it a spread of 16 pixels. And when it's flipped over, it's actually going to be the same deal, isn't it? It is. It's going to be the same deal. It's going to do the same transformation except I think what we want is we want the opacity to be zero here. Oh. And then when it's flipped, we want it. So we want it. We're going to get a crossfade here, all being well. I'm going to make it 0.2. We actually have to animate not just the transform, though. Wait. There should be shadow four or two people because you have shadow. No. I'm stupid. You okay? Yeah. You feeling good? You're saying it out loud. You realize that you're wrong. It's a great feature. That's why some developers have an actual rubber duck on their desk. And if you have a problem, you have to introduce yourself to the rubber duck and explain your problem, and they will most likely figure out what the problem is. He's my rubber duck. Because that's all I'm good for. You're not just good. So, okay. So now we're not actually seeing what I wanted to see. See? See I did something wrong. You did. Well, I'm easily confused. Yeah. I've got to set the opacity to zero as that there. I think. Yeah. So the other one is not showing up. And the reason is not showing up because in the JavaScript we've not told it to show up. So we need to grab hold of the 12 pixel shadow. Like so. How are we doing for time? We have another one. We're doing fine. Yeah. We're good. We're fine. I'm not sure where I want to go with this eventually, but this is like pretty decent, I guess. Yeah. Last list of null. Where are you? Oh, I haven't. It helps if you put it in the dom pole. There you go. Ah. Can't do anything that doesn't exist. Look at that. Slow it down. Slow it down. We could totally get away with it. That's the thing. If you slow it down you'd be like it could be better, but at 100% speed. And if nobody's expecting it, well the first time you show somebody and they're like, what have you made? And you're like, nobody expected. And they're like, do it again. You're like, no. No, I don't. At that point. I don't do my tricks a second, sir. At that point we'll just be clicking the buttons because it is actually so much fun. It is quite a lot of fun. Okay. How are we? We're good. Wow. Okay. Tell you what we'll do. A couple of things. Let's make it so it's a customizable color. Hey. Let's do color equals red. Which means? Go on. We've got a question. The question was why don't we determine the state of the shadow and the shadows by the already existing classes and elements instead of introducing new JavaScript? I think it's possible, but right now we don't want to juggle all of this in our heads or in your head specifically. It's shiny enough. There's two things here. It's true. There are two reasons why. One is that I didn't want to expose the class that it was open and expanded and whatever else flipped over on the actual element itself. Ideally. Ideally. So I had to make sure that it was going to be done here at this level. Now you could make a containing element, I suppose, for all of those and then use a single class. I mean, sure. I guess that would work. PR is welcome. Exactly. Yeah. We have gotten a lot of PRs on the repo. Actually, I didn't expect on our prototype elements to get PRs, but people have been... No, people do that. It's great. So you're very welcome to join us on the repo. I linked it in the chat. Good work, you. Not you. Good you. I know. Thank you. No, you did great. Right. So we can set a color attribute and we will or attribute as some people pronounce it. I've always been an attribute. Are you an attribute or an attribute? Attribute. Well, then again, I'm not even a native speaker. So what do I know? You know plenty. So what we'll do is we'll say this.color equals this.getAttributeColor. And that means we're going to have to have a setter and a getter. So we'll do setColorColor. Why not? And let's see this.color equals color. Now... I'm actually not up to date. Up to date. We can use color... Wasn't there a movement where we had every custom attribute had to be data dash something? Is this now fine? I don't know. If you know, let me know in the chat because I would actually like to know that. You seem good. But color actually exists, so it should be fine to use. Right. I think font color is actually, like font tag with color actually exists. This is gonna... I think this is gonna be fine. As long as it's gonna work. Yeah. The problem is I put red in here, but I could be like... I could put whatever I wanted in there. And you know what? We should actually totally handle that situation if we're going to do this. How do you do that? So yeah, I was thinking about this and I was like... Teach me, Paul. You know who's like really good about, you know, checking colors that you give to the browser? The browser's really good at it. So I was like, why don't we do like div? Huh? Huh? And then I can be like div.style.color equals color. And then if the div.style.color is empty because it didn't like it. Huh? We could do like console.worn and be like color. Not a color. Not a real color. Doofus. Well done. Passive aggressive warnings. This is what we call a British console. Well done. You. Hmm? Any other great suggestions? I should probably delete it. No. Keep it. If the style colors empty or just didn't like it, otherwise this.color. And then we can do this.style.setProperty. Set property. And then we could do that color that I did before. And then we can do color. Oh, I didn't know about set property. So all being well. Oh, we didn't like it. Hang on. Did it warn me? Oh, wait. I left it. Yeah. Not a real color. Not a real color. Well done, Paul. Good. All right. It came right back to bite you. It really did. I like that. Oh, there you go. It's red. Oh, it's red. There we go. That worked out just fine for us. And if we don't have anything at all, it's going to. Oh, we needed a point. It's going to say null is not a real color. Which, again, it's a bit over the top. So what we can do is just say, if there's not a color. I should put it. If there's not a color. Just call it a. That's fine. And so already fault color is going to be the one that is actually in the styles right now. Yeah, it's the red and purple. And then if you set it. Now, I suppose what we could do as well is if you change the attribute, we could just say if the attribute that you change is. Colour needs to switch case. No. Future proof it. Now we'll just. We'll return. Isn't it? What? Colour equals new value. Now that will do absolutely nothing. And the reason is I haven't told it to listen for that. So if I do $0.set attribute. Colour. Red. It's going to, you'd think that would do something. But because you mentioned earlier, I did the attribute change callback does rely on this observed attribute. So if we do. Yeah. And we do that. Damn. We're done. That's worked. All right. How we doing for time? We got five minutes. So then I can make the work with multiple ones. I know. Right. I was about to ask about the. No. Yeah. Because we're doing the good old flipping thing. There's things there in the DOM but on the screen about the accessibility. Yeah. No, I think if you're going to do something as overblown and ridiculous as this in production, you would want to watch first of all Rob Dodson's inert polyfill Ali casts episode, which is brilliant. Get hold of the inert polyfill and make sure that as the animation finishes with like a transition end, you'd set whichever side is not visible to inert, which basically tells the browser, you shouldn't be able to tab into this. It shouldn't show up for screen readers. Because as of right now, you could tap to the four buttons on the back. Even though we can't see them, you can still get to them, which is bad. So expect by the time this goes to GitHub, expect me to have added the inert polyfill. Rob, just posted that video in the chat. I wonder why. What a hero. See, look at that. Color equals one EA three, two, six. That's green. Don't know if I mentioned that. There you go. Now, the thing is, you remember back when I said that we were going to assume that the ripple was good. So that's not working anymore. And also while I'm here, it's quite annoying because I actually feel like I want to click on the ripple to get rid of it. I didn't notice how quickly I just added another one because custom elements. That's so good. So good. All right, let's do that. And we'll do if you click on the ripple. So now if I do that. Now there are two problems. One is that when you click on the green one, the purple one is still visible, which is bad. And secondly, that ripple isn't big enough. So we'll fix both of them. And we'll fix them in turn. And what I'll do just to make my life a bit easier right now, I'm going to do the flip switch. And I'm going to add a modal class. And I'm going to put a Z index of it on one. And then what I'll do is in the JavaScript, I will say when you do a flip, we'll say this dot class list dot the add modal. Fingers are getting tired. I know, right? All the fast typing. There we go. So that will then zap it over the top of that. Oh, that's pretty. That will zap it over the top of that. But the bad news is they've both got the modal class on, which means that we're back to where we were. So now what we need to do is in the add event listener, what we can do is we can say this dot container add event listener. Oh, add event listener. And we'll say on the transition end. Transition. Very underrated event in my opinion. That's really good. We'll say if this dot container dot class list dot contains, which is also incredibly handy flipped. So if this is the one that's actually at the end of it, so there are two transition ends. One when it flips forward, one when it flips backwards. The one where it flips forward, this class is going to be, that's going to be true, that if statement. So we can just return. Other than that, we want to say this dot class list dot remove modal because it's gone. It's the one that's when it's gone back. Okay. So we should see all being well. Yes. Good. Yes. No longer broken. That's good. That's one out of two. Well, that was, that wasn't broken. It wasn't just visually unpleasing. That's broken. Okay. Right. Let's do the other one very quickly. One minute to go. Um, the thing about this on resize is, is that it assumes that we're in the middle of the screen, which we aren't. So first things first. The problem is we also call it here in the constructor, which is a bad place to be calling it, because by this point it's not actually been added to the screen. So we, if we call that, if we call the on resize and we're trying to figure out where it is actually on screen, it's not going to work out too well for us. What we want to do is we want to do it in the connected callback when it's added to the DOM. In this case, we'll request an animation frame, which basically says wait a frame until this thing is definitely being added to the screen, to the DOM, all the styles and everything's figured out. Everything's up and running. And then call the resize. So that's one thing we're definitely going to want to do. Now, in the resize itself, well, mid-x and mid-y are no longer the middle of the screen. So we'll do const position equals this. .get bounding client rect, which is one of my favorite ever APIs. It's been around forever. And it basically tells you where this thing is on screen. It's width, it's height, it's left, it's top, it's right, it's bottom, it's brilliant. But be careful. It does force. It can do. If you've got pending styles, you've made a change to your classes or your styles, and then you call it, the browser has to go, hang on a minute, and you're going to apply all those styles. And then I'm going to run layout, and then I'll tell you where everything is on the screen. So be careful with it. In this case... So do all your reads, get all the dimensions, then do all the DOM changes, class changes. Bet your reads, bet your writes. Exactly. And in this case, I know there's going to be layout post a resize anyway, so I can afford to do this certainly here. So do position.left plus position.or width. Yeah. That'll take us to the middle of the box. And the same is also true for the top and the height. Now, the good news is that will sort of work for this one. Look at that. But it won't work for this one, because it's nearer the top left corner than it is the top right corner, and so we actually want to account for it, which way everyone's the max. Do you see what I mean? We either kind of go, you're going for the left corner or whichever one you're nearer is the wrong one. Go for the other one. So what we can do is we can say, let's have two new variables, because why not, rx equals math dot max, midx, or window dot inner width minus max, no, no, no, no, no, midx. There we go. Same goes for y. Y. There we are. There we are. Height minus mid y. And then rx, ry. Does that all make sense? Hopefully. Maybe you do the math. There you go. One, two. That looks good. They both work. They're customizable. We've done some showbiz. We're all out of time. Thank you so much for hanging out with us.