 Hello my friend and friends. Thank you so much for coming to join me for yet another video. And today we're going to be looking at how we can create buttons like this. I saw this shot by Patrick Hill over on Dribble. I thought it looked really cool and I wanted to remake them. So today that's exactly what we're going to be doing. And this is what we're going to be starting with right here, where I've sort of set up some very basic settings for the buttons, which we'll be looking at in a bit more detail shortly. I also screenshotted the different states that are here at the bottom just to make life a little bit easier to match without having to look at the gifts. So to start off with, I just have two buttons sitting here called glassy button in my HTML. So nothing too fancy there, which is giving me those two things. And I do have some basic styling that is on these, just to give us a bit of a starting point. There's nothing too complicated here. These two custom properties here are just referring to some colors that I have set up and I'll talk more about the surface one in a little bit. But I'm just basically using that to put the two colors using nth child. Don't use this for production with the nth child, but I'm in silly demo land. So I can get away with stuff like this. Now to go through this tutorial, we will be using a few more advanced things. We're gonna be using a lot of custom properties. We're gonna be using nesting and just the rest will be sort of some cool little neat tips and tricks and things. Nesting doesn't have the best browser support, but I'll explain it quickly and I'll link to a video in the description that goes into more detail and how it works just because browser support's not perfect. But in this case, because we're gonna have lots of different pieces, it is really going to help us stay a lot more organized. So the first thing we're gonna do is here inside of this glassy button, I want to create a hover state. So we're gonna come here, we'll make a hover and a focus. So I can say and hover and focus. I'm gonna use focus visible. If you don't know the difference between focus and focus visible, basically, it's just how most interactions work where it won't necessarily bring in the focus state. If you want more on it, there should be a card popping up and a link in the description just on the difference between what focus and focus visible are. And in here, we're gonna start off with a nice simple line and we can actually use a little bit of sort of modern CSS with where we don't have to use a transform, we can just come in with a translate now. And so when I hover, you can see it jumps up and moves down. Nothing too complicated there, which is great. Obviously, we do want this to actually transition and I'll just jump up and down, especially because that can lead us into like one of these awkward situations where it hops around. And obviously, we want to add a transition to this so it doesn't do that. But I'm not going to put it here and I'll explain why in a second, but just really fast if you've never seen nesting before, again, I'll put a link in the description on more information on how it works. But this would be the same as having my glassy button hover and then my dot glassy button focus, you get the idea, right? So the ampersand is a placeholder for the selector, the parent out here. And right now it's not super indispensable. But it's really going to come in handy sort of as we go through this with a few more things coming on here. But the problem with doing the translate here is the background is moving up. And just like you can see down there, we want the background to move down. Or yeah, it's going to shift down a little bit as the rest of it moves up to sort of create the different layers or levels within the button. So I don't actually want all of these things to be here. What we actually want to do is recreate that background using a pseudo element. So to be able to do that, and as I said, we're not going to need the hover and focus that are right here. So I'm going to delete those. And so I'm going to paste this in here, which is pseudo element that I already have set up. You can see that that's caused some problems because I have a position absolute on here. So I'm just going to come back up onto my glassy button, the parent, and we're going to do a position of relative, just so this is now the containing block. And then this positioning is an inset of zero, which is the top bottom left and right of zero. So it's now positioned with relative to the button instead of the viewport. We're doing the border radius inherit just so it matches the border radius here, which just makes our life a little bit easier. We set it there and it works anywhere we need it to. And the background color is coming through as well. Now one thing I'm going to do is on the original background color for the button, I am going to make this transparent just because by default buttons do come with a color on them. They have that like grayish color and we want that to go away. So transparent makes it transparent. And this will act as our background. The one thing we're going to have to do here as well is we're going to want to bring in a Z index on here, Z index of negative one. So it pushes it back behind our text, right? So we can actually see it. We're going to run into a bit of a problem with this, but it's solvable when we get there. But the advantage of doing this now is if we come and we're going to do our hover and our and focus visible again. Now here, if I do that translate, and we do our zero and negative 0.5 REM, so it's zero on the X axis, negative 0.5 REM up and down. So we'll move up by 0.5 REM and it's going to look like the exact same thing is happening. The advantage here now though is we can actually come inside here. And this is again, why nesting it comes in handy is I can come on that after right there. And on here, we can come in with another translate. And for this translate, we can come in with a zero and then maybe a 0.65 REM or something like that. So the offset's a little bit more and it's going to go down. So we're moving the button up and we're moving the after down. And that just makes everything work a little bit better there, I think, right? That makes sense to me. So obviously, as I mentioned before, we don't want it to necessarily jump like that. We want a little bit more to happen. So on the after here, I am going to also add this transition. And we're going to use, I'm going to put 200 milliseconds, it matched well with what we were doing. And then it's sliding down. The text is still jumping. I haven't put a transition there yet. Just because there's another little bit of a problem that's going to come up while we're doing this, which is let's just come actually on, right, when we hover, we actually need a white background on the text area, right? And we're going to do it semi-transparent. We can do the blurring effect and all of that. But let's say we come here on this hover and focus visible and we're going to give it a background. So background, let's just do coral right now so it really stands out, something that we can see. And when I hover on top, there's a problem. You can see that the coral color is actually behind the pseudo element. Even though the pseudo element has that Z index of negative one. And to really actually make this stand out, let's move that color to here. Let's do the coral here instead. And now the coral color is in front because we have the negative Z index, but then it jumps to the back. And this is one of those fun things with Z index, where we're creating a new stacking context. And this can be a little bit annoying for sure, but the new stacking context is being created when we do this translate right here. And that's because translate and transforms are one of the things, like if you lower an opacity, that would be another thing you can do that creates a new stacking context. And what that means basically is that the elements that are inside of this, even if they have a negative Z index, they can't escape out of it. It's a little bit like when we did the position relative on the parent to make this makes it a containing block. And then the position absolute is like contained within that space. The same thing is happening when you have a new stacking context, where the element can't actually escape outside of the parent anymore. So the blue ends up in front of the background, even though it wasn't here, because here there was no new stacking context. Frustrating, definitely. This is one of those times where this can be really annoying to happen. But because it happens, there is a luckily simple solution. Well, it's not, I guess it's a simple solution. It's not a difficult solution. We come on both of these, and we're just going to have to add a span here. I don't love having to do this, but it's as far as I know, this is the only way we can actually get away with it. Because we're going to need a few more moving parts here, potentially you could have the other background also as like a before pseudo element too. But just to deal with the text and everything else that's going on here, I think this is the easiest solution just to throw the span within there. And it's not something that's difficult to do, especially if this becomes a component or something like that. Then you don't have to worry about it too much at all. So let's jump back to our CSS now. And what we're going to do is we're going to remove the background color from here, we'll make this transparent again, transparent. And then here, what we'll do is we'll jump in and we'll add our span. And I don't need the ampersand anymore in the older syntax for nesting. You did need to include some sort of symbol at the beginning, but they've dropped that requirement. So I'm not going to use it here. And I'm going to add the background to here. Background color can be my coral for now and we'll fix the coloring in a minute. But there we go. We can see that that's working. And at the same time, over here, what I'm going to do is I'm actually going to come down here where we had this focus, the focus states here. And I'm just going to come here and add the span as well, because I want the span to be what's moving up during the entire thing. There is a funny thing here though, and actually learn this while making this video. And I didn't realize this before, you can do transforms on inline elements. Interesting, right? So now it looks like it's broken because this doesn't work on a span. I honestly, I never knew that until now. And I've been teaching CSS forever. Maybe it's one of those things that I learned and forgot, but I don't think I actually ever knew that one. So another interesting limitation. That's okay though, because we need that span to eventually be this entire glassy area. So that means we need padding and stuff on it anyway. So we might as well just come on here and say that this is a display block. And when I make that display block, now we can see that it actually moves up and down. So because of that, I'm also going to come on here, we can grab that same transition that we had, and I can put it onto my span. So we'll save, we'll go take a look, and now you can see that they're moving in opposite directions, and that's perfect. And so what I'm going to do is I'm going to take the padding that I had originally had on the button itself, and we're going to, we'll copy that line. And I'm going to make the padding here zero just because normally buttons by default do have a little bit of padding on them. So we'll put padding of zero there. And we're going to come down onto here now, and we'll add the padding on the element, or on the span, I should say, not the element itself. And we can also do the border radius of inherit here as well. And we get our buttons. And now we're sort of getting closer to that style where we have the separation that's going on between the two of them. Now, one thing that's kind of awkward here, and because we're going to have, we have a span that's nested, we have the after here that's nested, we're going to have another suit element after that's going to be on the span. And one thing I like to do when this happens is I don't want to have to hunt through my code if I ever need to make changes to these things. Like if I look at this, I would assume the padding is on the button. And then I looked padding zero, and that's kind of weird, you come back to this in six months, and you're just a little bit confused by what's going on. So we're going to take some of the things here and make them custom properties instead. So here on the glassy button, we can come and we can do this, I'm going to say padding. And the padding we had is my one ram 1.5 ram. And the other thing we'll do here is the timing of the animation. This one, just because we're going to be using it in a whole bunch of different places. So it makes sense to have it as a custom property. So for that one, we'll call it transition speed. And we can do the 200 milliseconds there. And that means my padding here will be my var padding. And I'm putting an underscore here. It's a little bit of the idea that layer veru had when it came to sort of private properties for custom properties, where we're just sort of saying this is locally scoped and not something you'd find in the global scope. And it just helps like if I'm looking for my button text, this doesn't have it, I know I can look in my root. Whereas here, they have the underscore. So if I find this padding somewhere, I know just to look in the parent and find the setting there. She used it in a little bit of a different way that just sort of helps encapsulate things a little bit more. I'll put a link to her article in the description if you want to read more about the idea. But I'm just going to use it like this. And then we can go and grab the transition speed here as well and just update these. So I'll do that really fast. So there is the transition there. And then we can also just drop it in right here. And anytime that we need to use the transition speed now, just to make sure it's always consistent everywhere, it makes it a lot easier when it's a custom property. Now let's get the the glassy look going a little bit here, because we're going to make we're going to split this off into two sort of sections. First, we're going to get the blurry effect. And then later on, we'll look at how we can add this greeniness to it, because it's a little bit different. It's not complicated by any means, but it's a little bit different how we're going to do that. But for the first part here, we can just go and find our span again. So let's go up. There's the span inside my glassy button. And here instead of using coral, the first thing we'll do is we'll just switch the background to be white. So we can do a zero, zero percent, 100%, which with HSL should make it white. And then we'll just come with like a point four. And you can play with how much you actually want that to be. You can see we have the the different colors that are coming through there. So that's perfect. And then we're also going to come through here, we're going to add a backdrop filter of blur and how blurry you want is, you know, we add a number there and then we get a glassy effect, which is kind of cool. Or it's a blurry effect, it gives us a little bit of that glass morphism style. But I think the grayness really brings it home, because it's like the frosted glass then, which usually is when you get the blurriness coming through. So I like that touch from this design. Now, the thing is, we don't always want that to be here, right? So what we're actually going to do, let's copy these two lines here. And I'm going to bring this blur down to zero. And I'm going to bring the opacity down to zero here. So it looks normal, everything's just kind of weird again, right, right there. And then we can do is we can come here, we have the focus invisible states. And on my span, I can bring those in. So the background color and the backdrop filter are coming in so that only affects us when we're hovering. Of course, now it's like a really weird jump. So what we're going to do is we're going to come back up to here where we have those we have this transition. And we just want to transition also our background color, right? And we want to transition the backdrop filter as well. So I'm just going to come on both of those, then we can copy this, paste those back in and put a comma. So now we're just transitioning all of that it just sort of smoothly moves in. Another thing that's important here, there's a few different things we need for the hover effect, but you'll notice that there's the background sort of shrinks down a little bit on hover, just to create more of like a separation between the color and the glass that we have, quote unquote glass. So to be able to do that, what we can do is when we come down here, we have the focus state again, we have my after, I'm also going to come in at a scale here. And we're going to scale it down a little bit, we'll try like a point nine five, or something like that. So just you can see how it scales a little bit down. Of course, when it's scaling down, it's looking good. I think my translate here is actually way too big. Right. So maybe a one, two, five, even something like that will probably match. Now, it's not exactly the same as the image that's there. But to me, that's okay that it's not the same as that image, just because it's going to move around a little bit anyway with our mouse eventually, that'd be near the end when we do that. And so because we have to get that movement in there anyway, matching the exact positioning of it right now doesn't make total sense. So I think that actually looks pretty good. We're just going to want to come back up to here where we're outside of the hover and everything. We have this one. I'm going to just duplicate this line of code and make this for my scale right there. And make sure this is a comma. And now when I do that, that looks a lot better. Right. That's much, much nicer than what we had before. So perfect. I'm really happy with that. Though I really think the graininess is what brings this home so much more. And we're going to see how we can do that in a second. But before we do that, I want to explore a little bit more with the custom properties, just to open up the controls for things a little bit more. And so what I mean by that is like right now, we have sort of our background color here, the blurriness that's coming through when we're hovering, and we're even going to have to change that a little bit for when we're clicking. So we're going to have another section down here for when we're dealing with all of that. And it's annoying. Again, I mentioned this already, but it's annoying if you're making these changes on an element or a component or something, if you have to go searching through all the different parts to be able to find when things are changing. So this is where I really like exposing things as custom properties. And it's, you know, let's make these things that I want to enable people to be able to tweak or change. And I say people, it could be me, it could be people on my team, whatever you guys, if you want to take this button and use it somewhere, it's easy for you to make adjustments to it. But I don't want everything to be easy to adjust. I only want certain things. And those are the things that I expose as custom properties. So the first ones we're going to expose here are these ones where we have the hover opacity and the pressed opacity, because we're going to have to add that press state in. And then the hover blurriness and the pressed blurriness. And the other one I want to add is also like when we do this, how far do these things actually separate. And so to do that, what we're going to do is we're going to come here and I'm going to add this in my hover offset and my pressed offset. So when I do this, how far apart are they going or like, what's the movement basically? And then the pressed is when I click, like, how does it move? And actually 125, I think we'll do like a 2.25 here. The one thing I haven't brought in here is the scale or the offset I have for the pseudo element. This is different things I'm going to put on. This is just the translate effectively that I have. Just because I think the pseudo element, we can leave alone. And if we're making adjustments and changing things, it's mostly going to be here that I think those would be worth doing. If you're following along and you think you should expose more things, by all means you can, if you think this is crazy and you don't want to bother with this, you don't have to do this. I just think it makes it a lot easier than when you have this giant wall of things with lots of different controls. I think this makes life a lot easier to be able to play with and make adjustments on. So what we're going to do is let's go and bring these into our layout now or into where we're using things. So that blur can actually stay the same, but we're going to come down here into my hover and focus. And here we had my var and that was my hover opacity was coming in here. So it looks exactly the same as it did before. The next is this one, which is my var and my, that was my hover blurriness. And so again, it should look exactly the same. Perfect. Then here we have my var and this one's going to be a little bit different because this is my hover offset, but I had that as a positive value up in my custom properties just because I think it's a bit easier to understand how to use it if it's a positive. Maybe I'm wrong on that, but you can see it's going the wrong way right now. And I don't want it to do that. So I'm going to do a calc here. And on that calc, we can just come in and then say times negative one. And I do this with my custom properties all the time where you make it easy up top and then you do your calculations and more complicated things lower down. So I'm happy with those. I think that's going to work well for us. As I said, I'm not exposing these just because I think even if we make adjustments, the way those work should be okay. But if you want to expose these things, you can. Now we want to bring in that active state. So when we push, we made those custom properties. We might as well use them. So here I have my purple bracket. And so I'm going to find that one here. And then I'm going to say and active. So active is when a button is actively being clicked on, or if you're using your keyboard and you push your enter or space bar, it's pushing your button is then active. So we're going to use our active state here. And on the active, we can come in. What do we want? The background color will change. The backdrop filter will not change. The translate will change. So let's just come here and copy all of these. Actually, we'll take this entire selector. Actually, we'll take all of these because all of this is going to change other than the backdrop filter. And here my hover opacity is this going to change to my pressed opacity. The hover offset will change to my pressed offset. And then here, let's just hit save actually. And so when I do that, you can see it's dropping down and the opacity is going down just because here the reason I'm dropping the opacity is you can see here it's a lot brighter and here the whiteness seems to go away a lot. So I'm dropping the opacity on it. And then here my scale, let's try a .9 because it definitely gets smaller. That looks pretty good. Maybe a .875 or something. We could play around with that a little bit. There, that looks good. I like that. And then the translate here could also change. So my translate, does it need to change? We could probably keep it the same actually. But if we needed to, maybe actually that looks a little bit better because we're keeping it a little bit further away. So I'm going to leave it like that and I'm pretty happy with it. The other thing that I had was the blurriness actually. So the back, so I think I removed my backdrop filter. For some reason I didn't think of it, but we do actually the backdrop filter. I don't know why I decided I didn't need to change that, but we did. We're going to use my var and it was my pressed blurriness. Right? And then if I come on that, it gets more blurry when we click down. Did I not change that? I did hover blurriness. I don't know why I thought I didn't need to change it, but I had that more blurry when we go down because it looks a little bit blurry or there, in my opinion. When you watch the animation, I think it's a bit more obvious. So let's just go look up here really fast. So this is where, you know, maybe this is E2 and this becomes a 12 or whatever you want. And then you can see it's less blurry and it becomes more blurry. And that's why I love exposing things here. This becomes a 3 and this becomes a 3 because you don't want it to actually change and then it doesn't change when you push down and all these different things we can do without having to hunt through our code. I love doing stuff like this. So I'll put it back to the values that we had because I think they match the design pretty well. But it's just cool that we can change all of these transition speed. We could change and everything is going to slow down. You get the idea. So let's go and add that graininess in. And to add the graininess, I'm going to go over to this website right here, which is grainygradients.vercel.app. I'll put a link to it in the description, of course. And this is super useful because you just get some controls that you can play with your size, your base frequency, your octaves and stuff. And it's going to give you graininess in SPG form, which can be really useful. If you prefer, you could definitely come in with a PNG or potentially even a JPEG here if you wanted to. Any of those would potentially work. I'm going to copy it here, so nice and easy. We hit copy. And then I'm going to go over to this other website, which is a URL encoder for SVGs. And I actually already have it there. But normally when you get here, you have a blank site and you just paste in the SVG that you have. And then you can come over here and copy the ready for CSS version of it. And that's going to give us this grainy texture that we'll be able to use and add into our buttons. So to be able to play with that now, we could put it directly on the span as a background image, right? Because this is coming in as a background image. If you paste it in your code, it will be a background image. The problem here is it's always there. It's also really dark. Whether you're doing this as a PNG or SVG or however you're doing it, you're probably going to want it as a background image. But background images are annoying that you can't control the opacity of them. Because that's really what I want to do now. I want to zero opacity and have it come in and be kind of faint. I don't want it to be this dark, intense, I guess. Because it's a little bit much. So for that, on my span I have here, this is the rate, the first nested span. So it's the span on the regular button. I am going to come in and we're going to come in and do an and before. So we're going to add a pseudo element to our span. And because it's a pseudo element, that does mean that we're going to come here and give it content. We'll do our position absolute. And we'll come in with an inset of zero as well. And then we'll throw the background image directly on there. And we can see it's working. Of course, there is a small problem now. It's in front of our text. So we can also come in with a Z index of negative one. And actually, when you do this, you probably will get this where it's sticking out. So just we'll throw that overflow of hidden on here as well, which I sort of snuck in there along the way. Because I'd run into a problem with my code and had to go backwards and forgot to remove that bit when I was recording. So there we go, though. Or it wasn't my code, actually, I paused my recording and forgot that I paused my recording and went on for like a little while. So that was annoying. But we're here and we're back to where we were. So we have that there. And now the big advantage is we can control how grainy that actually is by playing with our opacity. So we can come here and actually just say that this has will come at the bottom here. And we'll say this as an opacity of zero because we don't want it to be grainy here. We only want that to come in when we get that glassy effect coming on. And then this will want to transition in like everything else. So we will come on this with a transition for the opacity. And you guessed it, we're going to use my my we're going to use our var transition speed, custom property there. So when we bring in the opacity, it will transition like everything else. And just so you know, if ever you need to have a background image and you have to play with the opacity of it, this is generally the way to do it. Use a pseudo element and you position it and just have it there and play with the opacity of that pseudo element with the negatives and index. It's the best way to do it. Cool. So that's there. Now we can go and find our hover and focus states. Here's my span. And that span was on here. And now I have to remember if I did it as a before or after. And I think I did it as a before. So I can come in with my opacity and I can put an opacity and then the graininess will come in when I hover, which is awesome. But we're also going to want to change it lower down. And what I'm going to do here is I'm going to come and I'm going to make a variable called hover frostiness. It's a little bit of a silly name, but this is like it's frosted glass in my opinion. So the frostiness makes sense. I don't know if we need hover actually. I think the frostiness actually stays the same. So we're just going to do a frostiness like that. Right. So before opacity, perfect. We have my frostiness right there. And so we can come back up and we're going to come up to here. We have my offset, the blurriness will come here and we'll just come in with our frostiness frostiness like that. And let's say we want it at like a point four or something. And there we have it. If I come in, let's change that to like a point two, it's less frosty, three, it's more frosty. Right. So we can play with that number a little bit. And then when we click, just like this one, you can see the background is getting, we're going more, I think the point four is actually a bit high. Let's try like a point three point two, a little bit more. Oops, I used my keyboard there. We have it selected. There we go. That looks a lot closer to what the actual design looks like. I'm pretty happy with that. Perfect. I realized we don't have a border. We're going to have to add the border in or an outline. So we'll do it as an outline, I think, and we'll fix that weird thing. I'm getting there with like the bigger box. We'll fix that at the same time. I'm just double checking, but I'm pretty happy with how that looks right now. So I think I'm going to stick with that frostiness right there. Awesome. So yeah, let's, let's fix that. So let's come down here. And this is one thing you want to be very, very, very careful with. But on my glossy button, I'm actually going to come and I'm going to say that this has an outline of zero, which means when we tab onto it, we're removing the outline. Do not do this unless you have a very clear focus state on your items. Very clear. And I think in this case, we qualify because there's a big change coming in when I'm using my keyboard on here. So people should clearly be able to see what's being activated. Don't do this as a default, just because you don't want an outline on something. Always change the outline if you don't like the outline or come in with something that's very obvious. Don't remove outlines just because you don't want to have one there. Just saying that they're very important for accessibility reasons. But then what we can do is we can add that outline back on the span, but I don't always want it. I only want it on my hover state. So let's go find my hover, my focus, my span, and we can come here with an outline. And I guess it's one pixel solid. And then we'll do an HSL that's going to be white, but it'd be, I don't know, 0.5, maybe something that's not 2.7, 0.6, can play around with different numbers. But there we go. Just because I think if it's 100%, it's going to be a little bit too dark. It almost looks like it's not thick enough. That looks too thick. So I'll stick with one. And you can play with the number a little bit. That looks maybe closer to the design. You could also do this as a border. Just be careful if you do it as a border, you'd probably need to set a border up on the normal state as well, and then change the color of it when you're in the hover and focus because it could potentially cause some layout shifty stuff from going on because borders take up space, whereas outlines don't take up any space on the box model. But yeah, there we go. I think that's looking pretty good. I'm really happy with that. I think it's doing a pretty good job of matching the overall design. And yeah, I think it's coming together really well. We have to add that mouse movement in right now. But just want to say this is doing things like this can be so much fun to create and make things like this where you're trying to match designs because sort of like that thing I mentioned with the span, I never knew that despite teaching CSS for a decade now. And one of the things I love about trying to create stuff like this, it's just always an opportunity to learn a little bit extra, find new fun things that you can do. And there's actually another thing coming up in a little bit that for the animation to make it less janky, that I really like that we're going to be diving into that I couldn't figure out for the life of me and I'm super happy that I know it now. And it's one of the reasons I love writing CSS all the time, because I'm just always learning something new, speaking of always learning something new and staying on top of things. Today's video is being brought to you by Brilliant, which is a place where you learn by doing with thousands of interactive lessons and math data analysis AI and probably most relevant to you programming. The platform is put together to help you build understanding from the ground up with hands on problem solving where you get to play with the concepts that you're learning about. And as I mentioned, it's all about learning a little bit every day with bite sized fun lessons that you can squeeze into your busy schedule. Now we're about to jump into some JavaScript and if you're newer to web development and have been struggling with that jump into JavaScript, their thinking in code and creative coding courses are great for understanding how to think through problems and see how things like loops, variables and conditionals work. Now those two courses graduate into their programming with Python course, but those early ones are really a great way to set the stage for getting into JavaScript or any other language where you need to start to learn how to think like a programmer to give Brilliant a try for free for 30 days, you can visit Brilliant.org forward slash Kevin Powell or click the link in the description. And if you enjoy it, you'll also get 20% off if you decide to get a premium subscription. A very big thank you to Brilliant for helping support my channel. And with that done, let's drive into the JavaScript and have a little bit of fun with that. So the first thing is, make sure if you're following along that you do have a link to your JavaScript file, just called my main.js. And I have a defer here. I have it up in the head, but we just want the whole page to load. And then we'll go over to my JavaScript file. And we can jump over there. And so the first thing we need to do is get all of our buttons here. So I'm going to do a const of glassy buttons. And then we can just do a query selector all on that to get a, you know, all of our buttons. And in this case, we have the two of them. So I want to make sure it works for both. But if you're putting this into a bigger project, you might have more than just two. Now here, what we'll do is we want to go through each one of our buttons. So we can use a for each loop there. So glassy button dot for each. And then inside of some parentheses, we're going to do an arrow function. We're going to look at every single one of the buttons that's there. And we're going to do something. So we're using our arrow function. And I'm going to come inside the curly braces there and just go in a new line where now we want to do stuff. So what do we want to do for each one of those buttons? In this case, we're going to need an event listener on each one of them because we're going to have to pay attention to when the mouse is moving on top of the button. So to be able to do that, we're going to add an event listener that's not too complicated listener. And we want to be looking for a mouse move. And when we detect a mouse move on top of that button, we want to do something. So once again, we can have an arrow function. But in this case, I do want to put an e here. This is for late event, we want to keep track of the event because this gives us a lot of information about whatever's happening related to that most movement. Now coming in here, I'm going to add two more variables which are going to be my center y and my center x, which it's going to get the offset width and offset height of my button and divide it by two. And the reason for that is when the movement was happening in that original one, it was always based on the center and it would either go negative or positive, but it was like opposite of where the mouse was going. So this will open up that possibility because we're going to sort of focus everything based on the middle and my so we're just grabbing each button. And then we're doing the offset width. So it's finding the width and the height of the button and dividing it by two. So that number would give us the center of the element. Next, what we're going to do is find out how far away the mouse is from the center on both the x and the y axis. So to be able to do that, we're going to set my offset x and my offset y. So how far are we and this is always going to be offset from the middle. So for this to work, I guess we could even call that like middle offset if you wanted to. So we're getting, this is where we're using and actually I wrote e before and then we came in with our event. So I'm going to make that event. We're going to get the offset x and offset y of the event. And what that means is when we're here, it's going to be looking at the top corner is the offset is zero zero. So when my mouse is going on top of something, actually, let's find that well, let's look at that. It's a lot easier to explain through that. So we're going to do a console log. And yeah, we'll do a console log of the event offset y and x. So we can actually see what's happening here. So I'm going to do an inspect on that. And we'll go over to my console. And now when I'm on top of here, nothing is happening. Why not? Nothing's happening because I called this most mouse instead of mouse move. Hopefully some of you caught that while I was doing it. So with that in place, if we come over to here and I do my inspect in there, we get all of a sudden you can see some stuff is happening. And as I move that around, it's showing where my offset is. So if I go to here in the very corner, we can see that as I get there, we're sort of at a zero zero. And then as we come this way, we're increasing all the way down to the end there. So it's just showing us how far away from the top left we are. But we also know where the middle is. So that's why if we take these, let's just move this down here, and then let's change this to just my offset y and offset x. So now it's going to be doing this math here. And it's going to be giving us those. So if I come in and take a look, if I'm in the dead middle now, we're getting our zero zero is right in the middle of the button. And then as we go this way, we can see it's going more negative. And as I go this way, it's becoming more positive. So the zero zero is directly in the middle, which is exactly what we wanted to. So that's a good start right there. Now, how do we pass this down to move that pseudo element around? And for me, the easiest way to do this is with a custom property. Once again, we've been using a lot of them. And so we're just going to come in and I'm going to bring this in right here where I'm going to set each for each button, we're going to have a style and we're going to set the property and I'm going to call it x motion and y motion. And then for those they're going to be our we're going to use that offset x and offset y values that are here. And we're just I'm just adding pixels to the end here, because we need to have a unit for this to be able to work pixels will do the job perfectly, because that's the distance we're measuring anyway. This is going to be way too big. And there's two options here. One of the options would be to divide this number and make it smaller at this stage. And then it's always sort of locked in. And that's fine. I'm going to be doing that in the CSS and I'll explain why I'm deciding to do it that way. But I'm going to play around with that on the CSS side of things. So to make this actually work, there's actually two different ways we can make this work to. And this is that fun thing that I said I learned. And I actually broke my brain around this for a little while. And I'll talk a bit about how I found the solution because it was somebody else who helped me out with it. So I'll give them credit where credit is due. But before we get to that, yeah, what we could do here and this is sort of where I was first thinking about it, this would be on this part here, where we have the translate that's already happening. Now what I'm going to do in this is a cool thing. And this one I've known for a little while now that you can do. And remember, I said you have transforms and then you can do a translate there, or we can now have this as its own property. But what's really interesting is you can do both. So we can actually come in and do a transform and do a translate here as well. And it's going to keep this translate that translate still doing its own thing. And the second one is just manipulating it from wherever it was already, which can be really, really useful. And so for this one, we can close this down, we don't need that we want to come here. And it was the translate would be my var y, whoops, this way y motion. And then we can just copy that put a comma. And then it would be my x motion the other way. So we're passing those numbers that we're getting from JavaScript into being custom properties. And look at that, there we go. So you can see the movement is in the wrong direction right now. And it's way too big, right? But at least it's working, we're getting this interaction that's going on. And because the translate and the transform are separated from one another, the advantage here is that like if I'm right in the middle of this, if I can get there, but if I'm basically in the middle, it's going to sort of, did I put these the wrong way around left and right is going up and down, I think I did them the wrong way around x is x offset with feel like I did them the wrong maybe it's the other way around x is the first one and y is second, I thought it was the other way, but whatever. Yeah, that makes more sense left and right or going left and right up and down or going up and down. Okay, I put them in the wrong order. But yeah, you can see if I'm dead center in the middle, we still have that little offset that's coming. And it sort of follows us around. So it's never perfectly centered. But of course, the offset is way too big. But the other issue is, we're going to see this exaggerated now, like if I come on here, say we're jumping to where the mouse is, because we told it to follow that mouse position. And so this is where I got a little bit stuck and I was going to come in with some JavaScript solution basically to help ease the positioning of it a little bit that I really didn't like. But that's where Matthew wrote me back. I talked about it on Twitter. And he linked to this code pen, we're going to use the solution that he shared here, which is stolen from Anna Tudor. You can see here. And it's this idea that it will animate to your most position. And then we can move it around. And it follows the mouse. And then it will animate back to wherever we want it to be. And it's super easy to do. So thank you very much, Matthew, for helping me out on that because I knew there would be a trick to getting this to work. And I was breaking my head over it. And I'm really happy that I didn't have to come in with something overly complicated to get it to work. So the way to do this is instead of having this as a transform, like we have here, which makes sense. We're still going to keep it as a transform. But we're actually going to come down here and we're going to create some key frames. So we're going to do a key frames of enter. And we'll duplicate it once we're done. So we can say from. So the from is your starting point. It could also be a 0% if you'd prefer. And this will just be a transform of translate. And we'll do our zero zero because that's normally we want it just to be in sort of the default starting spot. Let's save that so it's not moving. We want it to start there. But if my mouse comes here, it's going to start there and just sort of animate over instead of instantly jumping there. And then we can come in with our two. So that would be the 100% if you prefer using percentages here. And that's where we can use that transform that we just created before. And I guess we could break this onto multiple lines because it's a little bit long. And so we have exactly what we just were looking at right there. And that's my enter. So we're going from zero to having that. And then what we're going to do is we're actually going to come and duplicate that and we can come in with an exit here. And we do need you can run animations in reverse. There's no issues there. The problem with running an animation, if you have an animation on something, you need to change the animation name if you want it to do something different, basically. So instead of running it in reverse, all we're going to do is take this from here and we're going to move it down. So it's after and we can start this as our from and make this one our two and you don't actually have to move them. The order doesn't matter. It's the keywords that matter or if you had a zero and 100%, it would work the same way. So it's going from wherever our mouse is and it's animating back to be there. So when we exit, we're going to do this animation. So first let's do our enter. So when we hover on there, we're going to come in with that animation. So we just come here and we can add it animation. And that was our enter. It will be a forwards. And it will take our var transition speed or is it transition speed? I forget what we called it. Yeah, so you can see it now before let's just take that. I can't take it off now. But actually, I'll just put it to zero seconds because this is effectively what it was before. We had zero milliseconds. So it instantly jumped when we were doing it. Now when I do it with the transition speed on there, you can see it actually animates to where my mouse is, but it jumps when we come off and we and here it just follows. It's so good. So it just follows our mouse and then it comes off. So it's perfect. But when we come off, we want it to do the same thing. So all that means is we add that animation to the normal state. We go find where that after was right here, the after. So this is the one when it's outside of our hover state. And we can just come here and add the animation exit and four forwards once again, and then the var animation speed, which I already have here so I can just copy and paste it and hit save. And now look at that. It works. So now you can see it follows my mouse when I come off, it animates back to there. When I come on, it's moving around. But of course, we're moving around way too much. So this is where we can come in with a few different ways to solve this problem. I personally think it's kind of cool to expose this one. So we're going to come all the way back up to here. I'm going to bring these together just because it's spreading things out a lot. But I'm just going to come in here with a motion factor. You can call it what you want. And I'm going to do a point one. And you can put a comment here of maybe like a zero to one. You can do comments. And a few of these actually we could turn into like this is also zero to one. The opacity here is a zero to one. And then we have these, I think it makes sense. The frostiness is sort of a zero to one. The blurriness we could turn into a zero to one scale with some calcs. So depending if you want everything to be that or you could just comment on the ones where a zero to one would make the most sense completely up to you. And so what we'll do is we'll use that motion factor down where we're doing our animations. And this is where it's a little bit confusing. I won't it's not confusing, but it's just it adds a lot more information here instead of doing it in the JavaScript. But the reason I like doing this again is it's related to the styling. I'm sort of passing in the offsets and then the CSS is figuring out what to do with it. If you prefer doing these calculations in the JavaScript, it's fine. But I just have so many different things up as custom properties now that I can manipulate and change that I find it weird if one of them was over in the JavaScript where I'd have to go and find it and change it there. So I like the idea of just taking the raw numbers, passing those raw numbers into the CSS and then having this be the area where there's changes in manipulation going on and making it easier to change those things through custom properties and everything else like we're doing. So all that means is here where I have these two. I'm going to come on both of these that are right here and we're going to come on both. So I'm just going to use alt to put my mouse on both of them. We're going to do a calc. I'll select all of that. And then we're going to do a multiplied by the var of my motion factor. And then we're going to do a times negative one to make it a negative number. So now, and the reason you want it, we wanted it as a negative is so it's moving opposite of where our mouse was. So if I go down, it goes up and now it matches the original design that we had. And once again, we come up, we can just take a look at how, and I guess the motion factor could be more than one. So we go back to one, it's going to be back to where it was, which is really extreme and kind of annoying. But, you know, we could come in here and do a 10 and it would just be kind of crazy. So I guess the zero to one comes off. But I would reckon I think zero to one is the safe zone and after that things will get kind of nuts. But if you want more movement, you know, a point two, whoa, whoa, whoa, I broke something there. So we'll fix that in a second. But the point two, oh, I know what it is. I know what it is. Okay, we'll fix that in a second. But here the point two, you know, you get a little bit more movement, point three, you get more and everything. So you can decide how much movement you want, how subtle you want the movements and control that through this, which I like. I think it just makes sense to do that. The mistake that I made was I made that transform change here, but I didn't make that transform change right here. So we need it in both the forwards and the backwards, and then you don't get that crazy weird thing going on. And it works perfectly. I'm super happy with that. I hope you enjoyed this video as well. A very big thank you to both brilliant for helping support my channel, as well as my enablers of awesome, Philip, Andrew, Simon and Tim, and all of my other patrons as well. And with that, of course, until next time, don't forget to make your corner of the internet just a little bit more awesome.