Build a Smooth Scroll Cards Parallax with Framer Motion and Next.js

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
there's this classic animation that I've been asked to remake multiple times and I actually see it in many many websites it's quite a simple animation but it's effective in its communication and it's actually really simple to make so I'll take a look at how we can remake this mainly by using the sticky position but I'll spice it up using fir motion all inside a nexj application and as always you can find the live demo and the source code in the description below all right so I have a very basic nexj application here I've deleted everything inside of it and we should have a blank page like this perfect to start this tutorial and now the first thing I did also is create a data.js file and here I basically have all the cards that I want to create and so if I take a look at the demo I have a card two card three cards four cards and five cards right and so every single object here in the projects array represent one of those cards and so I have the title description the source of the image Etc and so the first thing I can do here is import the projects from that data file and so I'm just going to get it here and then here what I can basically do is map the projects and so I'm going to have the projects in the index and here I'll basically return another component that I'm going to called card and so I'll go in the source folder and I'll create a components folder and inside of that components I'll create a card folder and inside of that card I'm going to have an index and a stylesheet and here I'm just going to initialize a basic react component and I'm going to give it a style and I'm going to call it the card and if I go back here in the root which is the page.js the first thing I need to give to the card here is a key and this is basically an ID so that react can properly identify all of the different cards s and so I'm just going to give the index as the key and then I also want to give all the information contained in the data file so the title description Etc I want to give all of that information to the card component so what I'm going to do here is deconstruct the project so I can do this that way and now inside of the card I'm going to have all of the different keys from the object here so I'm going to have the title the description The Source the link and the color and here I'll just return a paragraph with the title see what we have and one last thing I need to import the card here from the components folder that I just created and inside of the cards components I'm going to import The Styling here and we should have something like this very simple we are mapping all of the projects returning a card for each one of them and inside of the card components I'm returning a title and so that's what we have here and now I'll start creating the card so I'm just going to remove the paragraph here and I'm going to create another div and I'll also add some Dynamic styling so I'm going to set the background color to be the color specified in the data.js file and so for example the first card should have this color the second card should have this color and that way we can have like a dynamic color and then I'll just go into styling and here I can specify inside of the container we have a card and here that card I'll give some width and height like 1,000 by 500 something like that and we should have something like this we have all of our cards with the corresponding colors and then I'm just going to remove here we can see that there's like some margin and that's in the global I can do the body and I'm just going to remove the margin here so that it's flush and now that looks much better and I'll go ahead and make those cards sticky so the first thing I can do here is the card container I'll give each one of them a height of 100 viewp height and we have something like this and I'll just Center the card inside of the container so I'm just going to do display Flex align item Center and justify content Center and that way it's perfectly centered inside of the container and to make that card's container sticky I'm just going to do a position sticky and to make the position sticky work I need to specify a top I'm going to do top zero and also just for the sake of explaining the main here which is at the root inside of the page. J I'm going to add some styling and I'm going to do a margin top 50 viewp height and then if I inspect this we see we have the main here with some margin and then we have all of our card containers right at the bottom and we can see that the first card here I'm going to scroll and when it reaches the top at zero pixel it should stick and so I'm going to do it and then now it's sticky and now we have the second container coming in when I scroll and it's going to stick stick stick stick and when I reach the bottom here I'm going to add some more margin so we can see how it looks like when I reach the bottom so I'm going to do margin bottom 100 VIP height and if I try this again I scroll stick stick stick and then after the last one it should unstick because all of those sticky positions are based on the Main and the main actually ends here and so after that everything goes up and we should have something like this which looks pretty good very easy and also to me this is a bit too much centered in the screen I would like my card to be a bit higher up so very simple here I'm going to do position relative and I'm going to do a top minus 10% and now it's placed a bit higher which I prefer that for my own taste and one last thing I can add some border radius of like 25 pixel and now my cards are rounded looking good okay so I skipped the step here I've added some HTML and some extra CSS here for the inside of every single card to me this is basic CSS and HTML so I'd rather skip that part not to waste your time because personally I prefer to focus on the animation but please let me know in the comments if that works for you if you want me to take a look at the CSS part of this just let me know so we should have like the same thing that we had before but now with like content inside of it so if we look at the demo here there are three animations that I'd like to make now the first one being as you can see when the card comes inside of the view there's like an animation on scroll on the image so the image has a bigger scale and it scales down as we scroll that's the first animation there's a second animation which is as you can see the card is getting scared down the more we scroll to create kind of this overlapping effect that's the second animation and the third one is like the smooth scroll right so I'm going to take a look at those three animations now so the first animation I'll take a look here is the scaling on the image I'm going to do that with frame or motion so I'll go inside of the card component here now I'm going to start by importing motion and the use scroll Hook from FR motion so this is basically my image here I have an image container and I have an inner and inside of it I have a next image so looking at the styling here I have an image container with some styling some width and some height and I have the inner just taking the full height and the full width and it's this guy that I will animate and since the image container has a overflow hidden we can scale that inner as much as we want and it won't go past the borders or like the limits set by the image container so now you understand why I'm going to animate the inner component so I'm going to add a motion in front of it that's the first step to animate a div using fir motion and then I also want to initialize a use C hook so now it's going to get a bit more complicated I'll create here a container using the use ref from react and I'll initialize it at null and here I'll import it and now that container here will basically be the cards container so I'm going to just do that like this and also since I've started using the use ref hook I need to specify here since I'm in nexj that this is a client component and so I'm going to do use client here and now to scale the image on scroll I need to find a way to track the progress of the scroll and so what I'm going to do is use the use scroll Hook from frame emotion and so what I'm going to do here is extract a value that's called The Scroll y progress and this is extracted from the U scroll hook and now that use scroll hook takes a couple of parameters or a couple of options the first one being a Target and so the target is what do we want to track inside of the window and so what we want to track is the container it's 100 viewp height of height and so it's going to be quite easy to track and so this scroll wi progress returns a value between zero and one depending on where the container is according to the window and we need to specify a offet meaning when do we want to start tracking the container and when do we want to stop tracking the container and so we're going to have two values here the first one being an intersection and so it's going to be the intersection of here I'm going to do start and end now what that means is we want to start tracking the progress of the scroll at the intersection of the start of the container and the end of the window now this might be confusing but really what that means is let's say we have a second card here that's coming as I scroll and what we're tracking is the card container right so the start and the end here is basically the start of the container which is the top here and the end here is the Windows object and so it's going to be the end of the window here so what that means is as soon as the card container enters the view then we want to start tracking the scroll and so as soon as it enters the view here boom it enters the view the scroll wi progress will start at zero and as I scroll it will go up to one and so we need to specify a second object which is when we want to stop tracking The Scroll of the progress and that's basically when the card container is going to reach top of the window and so that value is the start of the card container and the start of the window as well so it's going to be start start and so now we have a value between zero and one that's basically tracking the card container where it's at as we scroll and now to illustrate that for you guys since it's a bit complicated at first I was quite confused with the offset particularly I'm going to add a very simple styling here on the inner of the image and I'm going to specify an opacity and so the opacity here is going to be equal to the scroll y progress and that way you have an understanding of that value so I'm going to save this and so if we take a look at this I'm going to inspect the inner here and you can see that the opacity is now at 0.5 and that's because the card container of the first one here is already at 50% inside of the viewport right and so the scroll progress is equal to 0.5 and so now the opacity of this image here is at 0.5 and you're going to see as I scroll it's going to boost and it's going to reach one when that card container reaches the top of the window and it's going to do the same thing for the rest you're going to see that at first the image is almost at opacity zero and as I scroll it's going to reach opacity one and check ET for everything right but now obviously I don't want to change the opacity of the image I want to change the scaling right so I don't really want to have like a scaling of zero that's going to go to a scaling of one just like that opacity that wouldn't make sense I want to have initially like a bigger scale and that's going to scale down to like a scale of one so to do that I need to use another hook which is the use transform Hook from FR motion and here basically it will allow me to transform the scroll wi progress into a new value so I'm going to have here the scale which which is going to be equal to the use transform and here the value that I want to transform is the scroll y progress and we know that the scroll y progress is a value between 0 and 1 and so we want to transform that value when it's inside 0 and 1 we want it to be 2 and one so what that means is we now have a scale that's going to be equal to two when the scroll right progress is at zero and it's going to be equal to one when the scroll y progress is at one and it's going to take every single value in between those two values as well so let's say the scroll wire progress is at 0.5 then we can assume that the scale here is going to be equal to 1.5 and so now that we have this new value here I can use the scale change the styling here of the inner and I'm going to do scale is equal to scale but instead of doing that I'm just going to do scale like this and it works as well and so let's see what we have if I scroll you're going to see that the scaling of my image now changes I have a bigger scale at first and it's going to scale down to one at the end of the progress of the scroll and so we should have something like this and it also works in reverse and so we have this nice simple effect with about three lines of code now I'm in the demo here and I want to take a look at the second animation which is the stacking effect here as we scroll there's like a small stacking effect now I'm going to use firm motion as well now for the stacking effect the first step is going to be quite simple we're just going to change the top property of every single card so as we can see the first card here has a top of minus 10% and the second card as well they all have the same but we're just going to set a dynamic top position using the index of each card and so the first thing we can do here is pass a new property to the card component and we're going to pass the index being the index of the card and so now in the card we have access to the index here and we can use that index to create a dynamic top property and so here I'm inside of the card and I'm going to specify a top it has a 10% right but I'm going to add more so I'm going to do a calc and I'm going to add 25 pixel right and I'm going to use the index and I'm going to multiply that by 25 and so now every single card will have a different top position the first one will have have a simple top of - 10% the second one will have - 10% plus 25 third one will have - 10% plus 50 Etc and we can see what we have here I'm going to scroll and as you can see there is a slight different top property here and now we have a nice stacking like this now there's another thing that I want to do which is a bit more complicated is to scale every single card as I am scrolling and that way we're going to have an effect similar to this where we can see that those cards are scaling after they reach their sticky position position the first thing we want to do is basically the same as the card component but we're going to put it in the root here so we're going to have one other progress of the scroll which is going to track the progress of the whole animation so here I'm just going to import the motion the U scroll from FR motion and then I'm going to have a container which is going to be equal to the use ref Hook from react and then I give that container to the main and then I have a scroll y progress which is equal to the use scroll hook just like we've seen before and here I'm going to give the target is the container same thing as before and now I need to specify an offset this is always the complicated part of this hook and I basically want the first scaling to happen at the beginning here so I know it's going to be start start at first the start of the container and the start of the window and when do I want it to end it's going to be at the end here when this guy reaches that point I want to stop the scaling and so that's going to be when the end of the main container reaches the end of the window so it's going to be end end and you can also use this snippet of code here to log the progress of the scroll if you're curious oh this is change if you're curious to see what it looks like so I'm going to do that just to show you guys okay so we have an error here we need to specify that this is a client's component because we're using hooks right so I'm going to save that and here let's take a look I'm scrolling nothing is logging because the scroll right progress is not changing and then it's going to reach the intersection of the top of the start start and it's going to start tracking boom okay so I have a lot of values here I'm just going to specify the current so let's do this again and and here we can see at the beginning it's zero and the more I scroll the more it's going to reach towards one and here right at the end when the last card reaches its sticky position it's going to do one right so that's exactly the range of value that we want for the scroll wi progress so I'm going to remove that here and now there's a couple of things to specify here the first thing for a single card is going to be a range okay we're going to give an object which is going to specify when do we want to start the scaling and so if we look at the demo here we can see that the scaling only starts when the card reaches it sticky position and before that there is no scaling and so that's why we need to specify a range to say when do we want to start scaling down the image because we don't want to start scaling it right at the start only when the card is sticky and so that's going to be quite simple we're going to give an array first being the start second being the end we know that the end is one it's the end of the animation so that's pretty clear but the beginning now that's the question and so I know that my indexes are between 0 and four and so if I divide 100 by 4 it's 25% and so I can do the index multiply by 0 0.25 and that should give us a range for the first card of 0 to 1 the second card will be 0.25 to 1 third card 0.5 to1 Etc so that's basically the range of the scroll y progress where we want to animate the card I hope that makes sense and then the other value that we need is a target scale and that's because every single card won't have the same scaling right if we look at the demo the first card here because it's the first one it gets scaled way more than the last one which is not even being scaled at all and so that's the logic all the cards have a different Target scale we can create here a Target scale value and here we're going to use some math I'm going to do one minus the project. length minus the index I'm going to put that in parentheses and multiply that number by 0.05 and then I can use the target scale and give it here to the card component and so now the target scale starts at one and it's reduced by the project length minus the index and that's basically the first cards will have a higher value here so let's say we are at the second card which has an index of one it's going to do project. length 5 minus one 4 multipli by 0.05 20 well 0.20 and then 1us 0.20 is going to be 0.8 and then one last thing that I'm going to pass is the scroll y progress which is the global progress of the animation and I can give it like here the progress will be equal to the scroll y progress and now I can go inside of my card and here I have access to the progress to the range and to the Target scale and so with all of that I can create a new value with the used Transformer hook but just before not to be confused I'm going to change that value here to be the image scale just so we're not confused scale is the image scale here now I'm going to create a property which is the actual scale of the card and that's going to be the use transform now instead of using the scroll right progress of the local card I'm going to use the progress of the whole animation and so I'm going to transform that value and here I need to give a range and I'm going to give the range that I've just created before which is that value here here that array here and then the third value which is the output that I want for the scaling will be one at the beginning and it's going to go towards the target scale and then I'm just going to add the motion tag in front of the card and inside of the scaling here I'm going to add the scale simple as that I'm going to save this and see what we have okay it's giving me an error I is not defined okay here I've used the index when really the value is index here so I'm just going to change everything to I okay there's another error here the length isn't of the project but it's the length of the projects that doesn't make sense project here doesn't have a length it's the array of the whole projects that I want to track here so I'm going to save that and I'll let's see what we have this should be working so now we have this nice animation on scroll and one last thing that I want to add is a smooth scroll on top of that and that's the easiest part of this tutorial the cherry on top of the cake so I'm going to use the lenus scroll to create the smooth scroll it's actually really simple to use I'm just going to pop a new terminal here now I'm going to install that now remove I need to remove the dollar sign here now I'm just going to install that and then inside of the root inside of the page.js I'm going to import the lineus scroll and then very simple I'm just going to take their setup but I can't just put it like this because I'm in nextg so all this code will be server side so I need to put it inside of a use effect for it to work and I don't need to log the event this should be it and now I have a nice smooth scroll with the scaling animation on the image and on the individual cards that's basically the animation I hope you learned something if you like the video leave a like subscribe and I'll see you in the next one bye
Info
Channel: Olivier Larose
Views: 5,657
Rating: undefined out of 5
Keywords:
Id: am0ZueQmpzg
Channel Id: undefined
Length: 18min 26sec (1106 seconds)
Published: Sun Nov 19 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.