Beautiful Animated Nav Bar with React & Framer Motion

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
if you've watched many of my videos you'll have heard me use cal.com for a number of different examples for a cool landing page a Cool brand and a lot of cool interactions and animations I just love this kind of like tactile almost paper-like feel that they've been able to build into their brand and for a while now I've been wanting to start breaking down some of the cool interactions and animations they built onto their landing page I figured a good start would be something like this navigation bar up here at the top it has this cool animated pill that actually follows your cursor around whenever you Mouse over different sections and we can recreate this effect Rel ly easily using react and framer motion enough talking about it let's go ahead and jump into some code taking a look at my code I've already got some basic layout Happening Here with styling using Tailwind CSS if you're not using Tailwind CSS not a big deal feel free to use whatever you want we'll make sure that we actually go over all of the styling that's going on here so I've got a wrapping component right here this could just well be your screen like your page and for this I'm just taking everything putting it in the middle of the screen and giving it some background color so nothing crazy going on here for our main slide tabs component right here I just have an unordered list which is rendering a number of list items that's these tabs right here obviously for your example you could use anchor tags or whatever it may be but for this example I'm just going to use a basic unordered list this unordered list has a position of relative we need this because here in a second we're going to absolutely position a little cursor that's going to be like that little black pill background and that is going to need to know that it needs to be relative to this unordered list I've added a margin X of Auto again this is really just for this example to put everything in the middle of the screen display a flex just so that all of these tabs sit next to each other rounded full just to round out the borders a two pixel black border background of white and a padding of four pixels for each of my individual tabs it's a little bit more interesting stuff going on so position of relative with a zindex of 10 so that the text sits on top of that little pill that's going to be in the background here in a second display a block a cursor of pointer since this isn't an anchor tag or something some padding on the x-axis of 12 pixels and on the Y AIS of six pixels text of extra small to start and then on medium screen so above 768 pixels I'm just bumping those values up so on the x axis my padding is 20 pixels y AIS it is 12 pixels and then also the text goes up to 16 pixels I'm turning all of the text to uppercase no matter what's passed in and then the most interesting part of what's Happening Here is these two Styles right here so you'll notice that I'm setting the text color to white but the text still looks black which is kind of weird right well the reason that that's happening is because we have this mixed blend mode set to difference and essentially what this is going to do is it's going to take the difference of the text color with whatever is behind it so in this case it's just the white background of the Navar itself and it's going to kind of make that the color of the text so if you have white text sitting on top of a white background it's going to turn it black but what's cool is it's actually going to do the opposite of that as well so if our little background pill thing is black it's going to turn the text white and that's going to look really cool because if we have our cursor thing in the background and it's overlapping any of our text just the part that's actually overlapping is going to change colors that might sound a little bit bit confusing but let's go ahead and jump to the cursor part and we'll see that kind of come together so down here below my tab I'm just going to make one more new component called cursor and for now this can just return a list item like this cursor is going to be rendered directly under our tabs like this and I'm just going to drop the Styles in for this as well and we can go ahead and explain them so I've added a position of absolute because this needs to be able to move freely about the background of our navigation bar a zindex of zero because we need this to sit behind our tabs which have a z index of 10 on smaller screens I've given this a height of 28 pixels which this is just mapping directly to what I know the height to be for our list items you could also base the height for these based on the top and bottom absolute positions that's just not how I happened to do it for this example we'll notice also that on medium screens I've bumped that up a little bit then finally I've just given this a rounded full to make it all a rounded Edge as well as a background of black now we're going to notice if I save this that we don't actually see anything yet that's just because we don't have any height set up yet or width rather so we can fix that let's just say width is equal to I don't know say 36 and there we go now we can kind of see what I was talking about here so you'll notice that any of the text that is overlapping the black pill background turns white but anything that is not overlapping stays black so if we have a situation like this where the pill is just halfway overlapping some text only the half that is actually overlapping turns the opposite color now I don't actually want to control the width based on a straight value like this I want to animate it based on whichever one of these pills we're currently hovering over so to see how that can start to come together I'm going to remove our width right here and we'll scroll back up up to our slide tabs and I'm going to create a piece of state which I am going to call position so remembering to import U State that's going to look something like this I have three different values that I actually want to animate at any given point so I want to animate the opacity I want this to not be visible whenever we're not hovering over something I want the width to be dynamic based on whichever one of these items we're hovering over and I want left so this left of zero here to be based also on the left side of whichever one of these tabs we're hovering over we can set these to some random value to start so you can kind of see what's going on on so we'll say left of 60 maybe width of 150 and then an opacity of one and go ahead and pass these into our cursor like this now coming down to my cursor component can open this up and before I actually pass in these Styles I want to turn this into a motion list item so that we can animate this value later so if you're not familiar with this just remember to install frame or motion and from frame or motion you can import the motion component so that will look something like this what motion is going to allow us to do is prepend any of our just normal jsx elements so in this case this list item right here and turn it into a motion. li what this unlocks for us is a whole bunch of different things but for our specific example what this mainly does for us is gives us access to a prop called animate and this animate prop can just be passed in any set of styles and it will handle automatically animating between those different sets of styles for you so notice that this position value that we're passing in already directly maps to three different CSS Styles so all that we need to do is take our position and pass it into animate like this if we save that now we should see this starting to come together so we have our pill in the background it's slightly overlapping home so that turns white it's fully overlapping pricing so that turns white and now we can just change these values as we hover over different ones of our tabs and it will automatically handle animating between them for us to do this let's start by zeroing our values back out so we'll say left of zero width of zero and opacity of zero and then we'll take our set position function and pass that into each of of our tabs so that will look something like this just pass set position in and then down on our tab component we can destructure that and start animating this value now remember from our position that there are two specific values that we need we need both the width of the actual element that we are currently hovering over as well as the offset of the left side of the element based on the relative position of the parent so that's kind of confusing but for example if we were hovering over home right here the left offset is essentially going to be zero right plus maybe a little bit of padding so we're going to need that offset between the left side of this container and the tab if we were hovering over pricing it's going to be whatever you know 100 pixels or something like that from right about here over to the left side etc etc as you go down the line to get that value I am going to use refs so what we're going to need to do to get that value is store a ref of the list item and then whenever we Mouse over our list item we can pull those values directly off of that ref so just using a normal react use ref I'll say ref is equal to use ref import that from react and we can default this to null directly on our list item I will say ref is equal to ref like this and the event that we want this to fire on is on Mouse enter like this so just create an inline function like this and that should be fine if you're using typescript to make typescript happy you're going to need to do something like this so I'll say if not ref. current ref. current actually stores the current value of the reference then we're going to want to return and now we can start getting some of our values first off let's actually see how we can get our width of the element that's currently being hovered over now on any reference to an HTML element we're going to have a function called get bounding client wck and that's going to give us a whole bunch of different numbers for the size of our element so to see what I mean let's say const data is equal to ref. current. getet bounding client wrecked and sorry my dogs are barking to see what this actually gives us let's just add a console.log and log out our data I'll hover over one of my pills here let's say pricing and open this up and we'll see all the different fun stuff that this gives us so it gives us things like the height and the width of our element this is specifically what we need but it also gives us the position of the element on the screen unfortunately this is not the position relative to the edge of the container which is what we need we're going to have a different way that we're actually going to get that value so since all that we need is actually width from this piece of data I'm going to remove data and just destructure our value width and down here we can start animating that value so I'll say set position and we can pass in our width now we we also know that we're going to want to increase the opacity on Hover so we can set our opacity to one and this is now going to cover two of our three Styles both our width and our opacity but we still need to figure out how to get our left value let's start by just setting our left to zero so we can see that the width part works if I now hover over home we'll see that that kind of looks about right pricing it increases in size and this little pill is going to keep expanding to the size of whatever we're hovering over but to get our left value we're going to need to do something a little bit different so over here on left I'm going to remove my zero and there's a value directly on our ref called offset left so it's going to look something like ref. current. offset left now you definitely need to make sure that this outer wrapping UL right here is relative because offset left is just going to look at whatever the closest relative parent is and that's how you're going to get your value so setting this to left now we should see this starting to come together hovering over home and then pricing and then features it will now follow me around no matter where I hover so if I go even off of my element go all the way over to blog and there's no Distortion or anything weird going on whenever you hover over all of these different elements finally the last thing that we really need though here is we'll notice that whenever we remove our Mouse the element just stays there which probably isn't what we want so just to round this off I'm going to come back up to my unordered list and add one more call to on Mouse leave this is going to call a function like this and really all that I care about is setting the opacity back to zero so I'll say set position this can take whatever the previous value is and just spread that value in only overriding the opacity setting that back to zero with all of this done now hovering over all of my elements continues to work but as soon as I move my mouse off of the element it goes away if I move it back over here it'll animate from there no matter where I kind of go and add and remove my mouse it just keeps following me around now there's a bunch of different ways that you could extend this you could add scale to this you could add different colors you could make it rotate you could get all kinds of interesting just based on adding different cool styles to this but I will leave that up to you to play with as well as turning this into a full navigation if you wanted to add things like links I will also say that if you're interested in an alternate way of doing this also with frame or motion using layout animations check out this awesome video by Sam sakov he gets essentially the same effect that I have here but with a significantly different strategy for how he does it so if you're just learning frame motion it could be really cool to check out how he did it and compare that with how I've done it here the code for all of this will be free on my website both in JavaScript as well as in typescript just head to the link in the description and then hit code right here if you want JavaScript or typescript you can toggle between the two of those as well as a bunch of other cool components if you want to check those out anyways that's going to be it for me if you learned anything I would massively appreciate a like and a subscribe until next time peace
Info
Channel: Tom Is Loading
Views: 5,249
Rating: undefined out of 5
Keywords: tailwindcss, tailwind css full course, web development
Id: obib4ka06y0
Channel Id: undefined
Length: 11min 38sec (698 seconds)
Published: Tue May 28 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.