 The other day, I was answering comments on a recent video of mine, and had the thumbnail staring at me in the top right corner of my YouTube studio, and that code block in the thumbnail was nagging for my attention, and I just couldn't help myself, I had to try and make it with CSS. So in this video, we're going to see how we can use HTML and CSS to create this. Add just a couple of lines of CSS to make it 3D-ish, like we can see right here. How we can make it even more fun by adding a bit of JavaScript to make it interactive and follow our mouse, which makes it a lot more fun. And after I shared that I was working on this, people asked if it was possible to do this type of mouse tracking with CSS only, so at the very end, we'll turn off the JavaScript that we're using right now and look at a CSS-only solution to tracking a mouse and getting this type of effect. So we can jump right into VS Code where I have a blank HTML, CSS, and JavaScript file to get us started, but of course we need some code in here. So to start with in the HTML file, let's hit exclamation point and hit tab to bring in a starter here, and that is using emit to be able to do that, and then we can give it a title really quickly, and of course we also want to have a link to our CSS file too. Now we need the code for the code block thing that we're going to be doing, and we could create that ourselves, but it's a lot easier to use a tool to do something like that. So jumping on over to Prism.js, this is linked in the description below. We can scroll down a little bit until you find this try it yourself link, and you can just do a Ctrl F for that as well, and that brings us to this page where we can paste in some code here. Now with your code there, we want to scroll down a little bit and tell it that it's actually CSS code and not markup. So just make sure you switch that over, and then we can right click in here and do an inspect. Once we do the inspect, what we are looking for here is the precode that is right there, which is exactly what we want. So we can right click on that, and then in here we want to go over to copy, and then we can just choose copy element right there. And with that done, we can close our inspector. We can also close down Prism.js. And in the HTML, we can just paste in the code that it's given us, which has a whole bunch of classes and stuff that make our life a lot easier. Now really quickly, I formatted my code here just to make it a little bit easier to see what we're working with, but we cannot keep it this way because we're in a pre, that means any formatting we do here is actually kept, so it would put new lines for everything here, which we do not want. But what I wanted to highlight here is this, we have a selector, we have a punctuation, a property class. So we're gonna be using these to style things. But because my grid was a keyword, for whatever reason, it did not give that its own span. It could be maybe a little bit easier to add a span and create something there that you could use to style when you're doing your CSS. But in this case, I'm gonna leave it like this to show a fun little extra trick that we can do within our CSS to handle edge cases like that. And with all that, let's just take all that formatting back off to exactly what we started with because it is very important that you have no extra spaces you pasted in and leave it exactly as it is. I find even working with WordWrap on makes it very complicated. So whatever, it's not too bad. We know a property's punctuation and selector that we have to work with. So opening up the browser, we can see what we're actually working with here, which is not very much to start with. So let's go over to our CSS and make this look a little bit better. Now on the body, I'm just throwing some things in here quickly to give a background color and also to center this pre on the screen. The parts that are centering it are right here. The rest of it is just the background color. And if you do want the finished code of this, it is linked in the description because this doesn't really matter too much. But if you want to look at it in more detail, it is there. Next up, we're going to go with these three custom properties here, which are the text colors that I used in the thumbnail I created. So of course you could use your own or do something different here if you want. And last before you dive right into things, of course, having the box sizing border box reset always helps out. I don't actually know if it would make a difference with what we're going to be doing in this one, but it's just sort of one of those defaults that I put on all of my projects. Now we can get to the fun part of actually styling up the pre so we can go in there and do a little bit of work. So to begin with just some basic styling for font size, font weight, our background padding and a border radius on there, nothing too fancy. But then we can get into the fun bits where we're going to start styling up the text to get the colors to be the right colors. And to do that, I'm going to be doing this where I'm using some custom properties and I'm just referencing the ones above. So we have a selector, a property and a punctuation there just to make it easy for me to know which one I'm using each for. Then we can assign each of those to the correct selector and get the colors to be working. And that just makes it easy if we ever want to make changes to either change things up here or go all the way to the route and make little tweaks up there as well. Now there is one problem with this, which is if we look at the colon that is right here, it is the wrong color compared to what I did in my thumbnail. And that's because it's following the punctuation class. Now we could leave that like that. It would not be a big deal, but there is a fun trick that we can use to get it to match my thumbnail more closely. And that is using the adjacent sibling selector, which is the plus symbol there. So that's saying if there is a punctuation that is following a property, its color is actually going to be the same as our property, rather than having the punctuation color on it. And as we can see that is working perfectly, the colon has changed over to the same blue as display. And if you like tricks like this one with this combinator and you're someone who's moved past the basics of CSS and you're looking to take the next step from there, I do have a course that you might be interested in called CSS demystified that helps you take that next step. There's a link to it in the description if you'd like to learn more. And with that let's get to adding the glow to our text. Now, I don't even know if the glow is the nicest thing in the world, but I had it in my thumbnail. So we're going to be adding it in here. But it's actually really easy to do with this nice trick where we can select every element that is inside of our pre and we can add a text shadow to it. The only problem with this is that obviously how can we control the color of each one? And there's ways that we can sort of try and hook into coloring and everything, but there is the original of the custom properties, which is our current color that we could use. And that we use the color of the text to be the actual glow. The one downside of this is that means we can't really control the opacity of the glow if we did want to turn it down, but overall I think it's copying what I did pretty well. I wouldn't use this on a regular basis, but I think that for something simple like this, you know, we're trying to recreate an effect, it works well. Now we actually want to get it to rotate and be 3D, which is sort of the whole point of all of this, right? So to do that we can add this transform right here. There's three things going on. We're rotating it along two of the axes and we've added a perspective which moves us away from things and makes the 3Dness of it seem a little bit more realistic. The number there, I just put a really big pixel value. I usually start at 1,000 pixels. In this case, it ended up being nicer. I just played around with it. I don't really have a hard and fast rule for a number, just experiment with what looks better. If you have one thing like this, it often doesn't really make a huge difference, but as soon as we start adding some actual depth with the other pieces in this, that's where that number becomes something that you might want to experiment with. Now, next up, we want to add that gradient background thing that we're going to be using. So let's scroll all the way down to the bottom to add this in and we're going to use my favorite thing in the world, Pseudo elements to be able to do this. More specifically, we're going to be using a after for the gradient, but we're also going to have a before used in here, so let's add both of those in. Now there's nothing very fancy, we're just doing a content for both position absolute and the border radius inherit, which is handy because it's going to make sure that the border radius always matches that of our pre, but because we do have the position absolute here, we will want to move up all the way over to our pre once again. And on there, we can add a position of relative just to make sure that this is the containing block and that after doesn't escape and use the viewport. So our positioning is relative to the pre rather than the viewport. So going back down to there, as I said, we're going to skip over the before, we're going to come back to that one after. For now, we're going to use our after here to add in that gradient background. Now I've put a very simple gradient on here and I've also put an inset of zero and that is short for a top, bottom, left and right of zero, meaning it's matching the actual size of the pre, but I'd actually like it to be a little bit bigger in all sides. So we can actually switch that over to a negative one REM and it's just going to increase it a little bit. So when we move it back, we will see that it's a bit bigger than our element itself. Now normally to move things back, you might be playing with Zed indexes or other stuff like that, but in this case, we're going to be working in a 3D world. So we can actually use a transform and a translate Zed, which is the forward and backward axis, like toward the camera or away from the camera. But if we want to be able to take advantage of that, we actually need to go back up onto our pre and add one more property. And that property is a transform style preserve 3D. And that's because when we have an element and we move it around in a 3D space, like we've already done with this pre, the elements that are inside of it are just these flat things that are on. It's like taking a sheet of paper and you're just moving a piece of paper around. The drawing on your paper is completely flat and it just moves around with it. When we use a preserve 3D like this, what it's doing is it's saying that actually the children of this are also living in this 3D space. So it's not like a piece of paper anymore. Now it's like a 3D, you made like a pop-up book. And the pieces that are inside of there can also live within a 3D space going forward negative and they're not these flat drawings that are on top anymore. Now just doing that does absolutely nothing at all but then we can move all the way back down to our before here and we can give it that transform that I talked about. And now we can see that it is actually moved behind our element and it's within the 3D space. If I turn off that preserve 3D that we had just before you can see now that Z index isn't doing anything because we can't pull back on a flat surface. We need that to also be living in a 3D space which this enables. If you wanna increase or decrease how things are doing you just play with the rotation on the parent and it should work but for now we'll go back to the 20s just so it looks a little bit easier to see what we're working with. And we're gonna do one more thing before we actually get to dynamically doing that movement with our mouse which is adding a little bit of a shadow underneath here and going back to 45 there might make the most sense to make it more obvious what's happening here. So let's go back down to where we were working before and that was where we had our gradient and we're gonna come here and now work on our before to add the shadow. So the first thing we can do is create our before and then I'm gonna move it in just a little bit for to give it a bit better of a shadow effect and I've given it a red background now just so it stands out clearly with the different steps we're gonna do here before we get it to be black. Next I can move it backwards and I've done negative 49 pixels just because the before has a negative 50 on it. If you'd rather they could both be negative 50 and then you could actually use your Z indexes to choose which one is on top of the other. So you'd probably do a Z index of like one of two maybe on this one and a one on that, whatever it is just to make sure that they're stacked properly or a one pixel difference on the translate Z. It should give you a very similar effect. No one's gonna really see the difference once we're finished with this. The next thing we wanna do is add a filter of a blur to make it blurry and lower the opacity of it a little bit just so it's not too strong. And then of course we change it over to black to make it into a shadow. And now it does look a little bit strong now but we're at a really extreme angle. It won't be so obvious most of the time but you could play with the blur and the opacity on this to muck around with it a little bit maybe make it a little bit less obvious if you feel like it's too much. Now with that out of the way we're basically ready to go in and actually make this work with JavaScript rather than with CSS. But the first thing we're gonna do for that is to come all the way back up to our pre where we set up our rotations and instead of putting in set angles here for both of them we're gonna put in variables. So my rotate Y is looking for a variable called rotate Y and my rotate X is looking for a variable called rotate X. Neither of these are defined right now so they default over to zero and we just get it looking flat at us like this which is perfect. That's exactly where you'd probably want it to start with anyway. Now we're gonna be jumping over to the JavaScript but really fast. I don't think I've linked that over yet. So let's go over to here and come right there and we can add the script tag for our JavaScript. Now hopping over into our JavaScript we wanna be manipulating our pre so first we can do our query selector to find that on our page and make that our const of pre. Next we can create a function called rotate element and in there we're gonna be looking for an event which is going to be tracking our mouse movement as well as the element itself that we're going to be manipulating. Now the very first thing we need to be able to do is to track our mouse position on the screen so we can do that like this mapping our X to our event client X and the Y to the event client Y and of course what is the event where we're gonna add an event listener to be able to keep track of where the mouse is. So to do this we can add an event listener with the mouse move. So we're looking for a mouse move anywhere on our document. So basically if the page is open and our mouse is on top we're keeping track of any movements of that mouse and what that does is it allows us to pass that down here in our rotate element which is going to be our event that is right there. So we're keeping track of everything that's going on and with that done let's jump over to our blank JavaScript file. And of course we always like double checking that things are working so we can come over to our page and do an inspect element and when we're there we can go over to our console and anywhere we move our mouse we can see we're getting the coordinates of where it is on our page. Now the pre is in the middle of the page and should be moving around based on the position of the mouse relative to the middle of the page. So the first thing we need to do is find the middle of the page. So we can do that with this where we're getting the window inner width divided by two and the window inner height divided by two. So we're getting halfway down that way, halfway down the other way which will give us the middle. Now next we want to get the offset from the middle. So how far away is our mouse from the middles? We can do that with X minus middle X and Y minus middle Y. Now of course if we want to take a look at what that's doing we can console log out once again and if we come take a look if I put my mouse close to the middle we're close to zero zero. The more I go this way the more negative it is because again we're doing X minus so we're getting a negative value there and the more I go this way the more in the positives we're getting up and down will mostly be affecting the Y value left and right is affecting the X value. Now ideally we're actually getting this as a number from zero to 100 or maybe even less so we're dealing with numbers that would work for a rotation. So to be able to do that we could get this as a percentage instead. So first we can add in dividing by the total which would be our middle X and our middle Y. So now if we come and take a look we'll get the decimals. So this is like a percentage where one would be 100% and negative one would be negative 100% and zero zero point five would be 50%. That type of thing going on. And to be able to now play with that what we'd wanna do is multiply these numbers by something. Now we could do both of these times 100 to get it as a percentage. Don't really want the rotation as a percentage though we're gonna be working with degrees and you just have to decide with the maximum amount of degrees you want our because if we get to the top right if we're getting to 100% this would be giving us one. So times what? If we did 100 it'd be 100 degrees if I wanted to do the maximum as a 45 then I just do times 45 and then I'm limiting it adding maximum of 45 degrees which to me makes sense but that number could be 10 it could be 100 it could whatever you want you could play with it to increase the effect or make it more subtle. So once again looking at our console we can see if I get to the top right we're dealing with almost 45s same thing if I go down that way we're sort of working within that range now. Now what we wanna do is update our custom properties using JavaScript so we can do this like this by selecting our element it's getting the style of it and then setting the property of my rotate X and my rotate Y. The one thing that's very a little bit awkward here is my rotate X is based on my offset Y and my rotate Y is based off of my offset X and that's because I'm tracking my offset along my X axis and along my Y axis. The thing with rotation in CSS is we're rotating along the X axis or we're rotating along the Y axis. So if the Y axis is here and I'm rotating I'm rotating this way and if the X axis is this way I'm rotating it across that axis. So we actually wanna reverse things around a little bit like this it's a little bit strange but for my JavaScript I feel like this makes the most sense because we're getting the X position and the Y position. We just have to inverse sort of how we're using those once it comes to the rotations. Now we do have one problem left because while it's working it works really well left to right but the up and down is actually the opposite of what we probably want it to happen because it should probably follow the mouse this feels really unnatural right now. So to be able to fix that remember the rotate even though it's the up and down which feels like it's my Y axis that's rotating along the X axis so that one we can do a negative one times that so we're just flipping this number around and making it the opposite and then by doing that now when we're rotating that it will follow the mouse anywhere we go. And I think that's really fun it's really snappy it follows the mouse really well but a lot of people when I first showed this asked about doing a CSS only solution which I wanna jump into it's a little bit different in how we have to do things but right before we get to being able to track our mouse with CSS only one other fun thing that we can do here is if we jump back to the HTML on this pre right here we can add an attribute that can make this a little bit more interesting and that attribute is content editable. Now with that on we can actually edit the content that's in here with the JavaScript sometimes it's a little buggy but let's see let's select this so let's say we do fun see there we go it's bugging out a bit but fun 3D effect and if I click off it should show up there we go fun 3D effects and you know what let's just turn off the JavaScript for a second and up try that again fun there we go 3D effects and it becomes editable the one problem with it is you can't really add new lines of code just because it won't it doesn't have the formatting coming from prism that we had of course you can do something with prism that maybe would help you be able to do something like this that could be interesting but that's a bit out of scope of what I wanted to do but I just wanted to show that we can do that and then of course if we turn that back on we have always saved so it refreshed but yeah it glitches a bit and as soon as it loses focus you get back what you had so anyway just a fun thing that you could add on there if you wanted to but I'm gonna take that off and now let's look at how we can do that effect that we had by turning off our JavaScript here and getting that same effect to work with CSS only so first let's jump on over to our HTML and actually take off our script tag so that is no longer doing anything now before we go over to our CSS to start making this work we actually have to make a change in our HTML to get this to work so the first thing I'm doing is wrapping this in a pre-container and you cannot change the indentation of these because if you do change the indentation it will change it there that's just how pre's work so you have to leave that you can't nest it the way you might want to next inside the pre-container I'm gonna do a div times nine to give myself nine empty divs this is how we have to do it if we wanna use a CSS solution without JavaScript you can get a lot more fidelity the more divs you use here so go crazy if you want to but we're gonna keep it simple for the demo here jumping on over to our styles let's go all the way down and in there I'm going to do a couple of things first I'm gonna have my pre-container with a position of relative because the divs that are inside there will have a position of absolute and I'm gonna use a grid template here with a repeat three of 1fr to give myself three columns and three rows that are going to be taking up all of the available space now when I first do that it's gonna break where my pre is on the page itself right now and we wanna make sure our pre is taking up the entire grid now for this part I'm gonna keep these styles separate from the ones we did earlier just so we know that these are the ones that are only part of the CSS only solution so to fix it and get the pre covering that entire grid that is on our pre-container we can do this with the grid template rows of one over negative one and we can do the same thing with the columns and the reason we're doing that with the negative one is line numbers go one, two, three, four but then the reverse order goes the other way where we have negative one, negative two, negative three, negative four so we're saying start at line number one and end at line negative one it just means go all the way across without having to count your line numbers and the same applies for the rows up and down as well now next we have to worry about all of those divs so I'm gonna select the divs that are the direct child of our pre-container I'm gonna give them a big Zed index just to make sure they do end up on top of everything that is here we're gonna give them a position of absolute and an outline for now just so we're gonna be able to see them even though we can't actually see them at the moment because they don't actually have any size yet now one thing that's interesting when you are using position absolute if the parent is a grid you can still assign it grid columns and grid rows and then use an inset of zero or a top, bottom, left and right of zero and it will actually get that element to be on the area you've defined so if we increase this here to say five pixels we'll see it very clearly that it's in that spot that we want it to be in now this of course means we have to set all of them up into the cell that we need them to be on so very quickly I've already done that where we just select each child using nth child and we set a different row and different column for each of them to get it to be exactly where we need each one of them to be now the real magic comes here and this is how we manipulate the X and the Y custom properties without using JavaScript which is why we actually had to set the divs up here right before the pre there is another way that is a little bit cleaner that you can do this with a has selector has selector doesn't have perfect support yet so we can still do it this way and what we're doing is we're saying if we hover on the first child here we're gonna set the rotate X and the rotate Y of my pre and so you can see now when I have her on top it's actually moving now I've set it to go the wrong way so there we go I fixed it so now if we go there into that corner we can see it's jumping up to where I want it to be now once again to get this to work we need to set this up for each one of the divs we created as I said we can get more fidelity if we have more of them but it takes more setup to do it might be much easier using a pre processor like SAS to be able to do something like that and we can see now anywhere I move along there it's going to rotate toward my mouse but of course it looks very chunky and ugly right now so if we scroll back up to the original selector of our pre we can add a transition and now when we have her on top it's gonna move around and be a little bit snappier so if we turn off her outline we can now see that it works pretty well and we can move around and as I said it's a little bit chunky just because we have only nine areas to move across so less fidelity than with the JavaScript solution but I think it's still pretty fun if you enjoyed this video you might enjoy another one where I looked at a fun 3D flipping effect where I actually spin the element all the way around in a 3D space now if that looks fun and you wanna check it out the video is right here if you're viewing pleasure and with that I would like to thank my enablers of awesome Jan, Johnny, Michael, Patrick, Simon and Tim as well as all my other patrons for their monthly support and of course until next time don't forget to make your corner the internet just a little bit more awesome