Build a Text Gradient Opacity on Scroll using Nextjs and Framer Motion

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this animation must be the most popular animation inside award-winning websites I've remade it in the past using Gap but today I want to take a look at how we can make this using firm emotion and next ja I want to take a look at three variations one starting with a paragraph I want to animate it on scroll and then I want to do a word byword animation and finally I want to do a character by character animation and as always you can find the demo to these animations in the description below as well as the source code all right so I have a very basic nexj application here and I'm just going to go right into it and start working on the paragraph and so I've already created the component here for the paragraph and I'm just going to go ahead and delete the div here and I'm just going to create a paragraph and here I can have like the paragraph and then I'm going to go inside of the page.js and I can have the paragraph here and I'll import it and we should see that it's imported now inside of the ph. JS and then I have my paragraph here which is just some lurem ipsum and I can take that paragraph and give it as a value to the paragraph here and then I can go back and I'll have the value here that I can take and put inside of the paragraph and now I have this and after that I can just add some simple styling I'll have a styles that I can have like the paragraph inside of it and here I can just do like a font size 50 pixel maybe like a Max width of like 1280 and then some padding and then I see that I still have the default font family here and to toggle that I'm just going to go inside of the layout and I'll remove the enter here and now I should see my font family and that's looking pretty good now I'm just going to add some spacing so we can have space to scroll so I'm going to go inside of the page. create a div give it some styling and just like a height of 100 D height I'm going to put one on top and one at the bottom and so now we have some space to scroll and it's a perfect start to start animating this paragraph and so like I said I'm going to use frame and motion to animate this and the first hook I'm going to use is the use scroll hook if you're looking to create scroll based animation with frame motion you got to know that hook really well so just going to go ahead and import that hook here from FR motion and I'll also import the USF Hook from react because that's the first thing that I need to create is a container or actually I'll rename it because it's not really a container in this case I'm going to call it the element and I'll initialize a ref at null and then I'm just going to give the ref to the paragraph here I'll just reformat that so it looks good like this and I'm just going to give the element and now it's giving me an error because I'm starting to use some client side hook and so I need to specify that this is a client component and I'm going to do the use client directive here and now the error should be gone and now I'm going to use that use scroll Hook and the first thing that I'm going to extract from it is the scoll y progress which is going to be equal to the U scroll hook and then that U scroll needs a couple of parameters and that's actually really similar to the intersection Observer API if you do like vanilla JavaScript maybe you have used that API it's actually really similar if you've used it before you're going to understand that very easily it needs a first thing which is a target which elements do we want to observe inside of the screen and well for us we want to observe the element which is the paragraph and then we need to specify an offset it needs two intersections and so the first first one I'm going to do start and end and what that means is it's the intersection of the start of the Target and the end of the container because you can actually specify a container here which would be a scrollable container and if you don't specify a container it's going to take the window as the container and so that value here in that case would be the end of the window and then we need to specify another intersection and here I'm going to do the start of the target but this time I'm going to do the start of the window as well so here I'm logging the scroll y progress as it changes to show you guys and you're going to see as soon as the paragraph comes in it equals to zero and then I'm going to scroll and right when it reaches the top Boom at this point it's going to be one and so now we effectively have a value between zero and one for the progress of the scroll and we can simply use that value directly as a style and so I can have a style and I can do the opacity is going to be equal to the scroll y progress but this is not going to work like this we need to add a motion tag from from motion and we need to add it in front of the paragraph because the scroll right progress here you can see it's a motion value it's not a number and so you can't give a motion value as a value for the opacity that doesn't make sense but if you add the motion tag in front of the paragraph then for motion will manage all of that for you and so I can save that and so I'm going to scroll and here the opacity is zero and then it's going to get up to one as I scroll and that's actually very easy to do and now there's another thing that I would like to tweak here is I'd like to wait for the paragraph to be a bit more inside of the viewport before I start animating the opacity that's just for my personal taste instead of doing the intersection of the start end here I'm going to change the end to be 0.9 and what that means is instead of being the bottom of the window it's going to be 90% of the height of the window and so there's going to be like a padding of 10% before triggering the intersection right so I'm going to save this takes a bit longer before the opacity gets triggered and that's what I want and also I would like maybe to have it at opacity one at this point here not necessarily at the end and so I can also adjust the second intersection and I'm going to do 0.25 which would be like a 25% starting from the top of the window it's waiting a bit before triggering the opacity and then I'm going to scroll and now the opacity here is at one a bit before reaching the top of the window which is something that I prefer personally for like the ux of the user and so yeah that's good now we have the first animation really basic and we're going to build on top of that for the second animation now the second animation will be the same as the paragraph but this time I'm going to split the paragraph in words now I'm going to animate word by word and so the first thing I can do here is import the word components from the components folder and then I'm just going to put the paragraph in comments here I'm not going to need it for now and I'm going to put instead the word component and I'm going to use the same value here and then I'll just copy paste everything inside of the paragraph components put it inside of the word components because it's going to be really similar we're going to use the same concept with the scroll progress it's not going to change I'll just delete here the logging I won't need that just delete the logging for the paragraph as well and so for the word by word animation the first thing I need to do is split the paragraph into individual words and that's really easy I can just have here the words is equal to the value which is the paragraph and I can do a split and I can split it by space and so that will now be an array of all of the words and now the paragraph here is not going to be animated anymore so I'm going to take the motion off take the styling off as well and the value instead of just putting the paragraph I'm going to have here a map of the words and so I'm going to map The Words which is going to return me as parameter here the word and the index and then here what I can do is return inside of a spound the word and I could have a key here as the index and we would have something like this looking quite weird but that's basically the concept we would have all of the words inside a paragraph here to fix that I just need to add some styling so I'm going to go inside of the styling here and I'm going to specify a display Flex a flex wrap and now that makes a bit more sense but now it's all squeezed up so I can add some styling for the word add some maybe margin right of 12 pixel and some margin top of 12 pixels as well and then I can come here and give some class to the spawn I'm going to call it like the word and so we would have something like this now it's too spaced out for me I'm just going to specify a line height of one and that makes more sense and now I can inspect this and I'll see that I have the same paragraph and inside of it I have all of my words separated as separated elements and that's what I want to be able to animate them individually and it's also good to note for accessibility purposes that I have a single paragraph and I have all of the span inside of the paragraph and so it's still considered a paragraph for like the Google crawlers and people who are blind things like that and so now that we understand the basic structure instead of having a span here I'll create another component which I'll call the word component and inside of that word component I'm going to return the span here and I'll delete that and have the word instead and I'll give the word as a children here and so if I go inside of the props I have the children and I can use it and that's that's basically an individual word and then I need to add a key as well or react is going to panic okay so now I have conflicting words this I'll still have it be called the paragraph and I'll remove the key here this doesn't make sense anymore and we should have the same result but now it's a bit cleaner it's in a different component and here I can add some things for the animation and now we need to find a way to animate each word one by one depending on the progress of the scroll and so I know that the result that I want to have is the more I scroll the more I want each word to be animated in a chronological order now with gap it's really easy to do that with the Stagger value but in frame and motion we need to find a way to add our own logic so we need to dig a bit into some math to figure that out it's not necessarily a bad thing because you'll understand way more what's happening like at the core and so I know that the scroll y progress is a value between zero and one and I can think about it as the progress of the animation and so it would be between between 0% and 100% And so I can think about it that way and say okay I want my first word here to be animated between maybe zero and 5% of the animation then I want that word to be affected by the scroll then after if we're at let's say between 5 and 10% then I want to be animated the second word and so let's say we were here maybe here we are at 45% of the animation and so we would be maybe at that word right and so what I will have for each word is a start and an end value and so I can think about the start as the index divided by the length of the whole paragraph and so let's say I have maybe 25 words here then I'm going to have my first word which is zero the index is zero first one here and I'm going to have it 0 divided by 25 is going to be zero and so that's exactly what I want I want the first word to be animated first when the progress of the animation is zero and then I can have an end when do I want that animation to end and I'm going to have the start and I'm going to add a step and now the step is an abstract value because I don't know in advance what will be the length of my paragraph right and so I'm going to have it be one divided by the length of all the words inside of the paragraph and so that's like an abstract step that is dynamic depending on how many words we have inside of the paragraph and so all of that sounds really complicated but I'm just going to log it it's going to be much simpler to explain I'm going to have the start and the end and I'll put it inside of an array it's going to be a bit easier to see and so here we can see this is the range for the first word and what that basically means is that first word is going to be animated between 0 and 4% of the animation and then the second word between 4% and 8% Etc and when we reach the last one it's between 95% and 100% of the animation and those values basically represent the scroll wi progress which is a value between 0o and one I hope that makes sense conceptually to you guys because that's how we need to think about the scroll when using fir em motion and so now that I have those values I can create a range and I'm going to have it be the start and the end and I'm just going to pass the progress of the animation as well which is the scroll wi progress and then here the word will have those values the range and the progress and here what we can do to create an opacity is to use the used transform Hook from fir motion and so that used transform hook basically takes a range of input and then it outputs a different range of the same length and so the value that we will transform here is the progress which is a value between 0o and one and then the input will be the range and the output will be a value between 0o and one and so what that means means is let's say we take the second word when the progress is between the range that we have here so when the progress is between 0.04 and 0.08 then the opacity of that second word should be between 0 and one and so I'm just going to add some formatting here and I can put the motion tag in front of the spawn and I'm going to have the style here and I can specify the opacity to be the opacity and now I can try this out and I'm going to scroll and you're going to see that every single word is being animated depending on the progress of the scroll but now it looks a bit weird because the words are just popping like out of nowhere and so what we need to have a nice effect is to have a shadow and so to create that shadow I'm just going to create a parent another span because we can't be using divs since we are inside a paragraph if you try to use a div inside of a paragraph it won't work so I'm going to have the span and here the class word I'm just going to give it to the first span and then I'm just going to remove that like this and here I'm going to add another span for the Shadow and here I'm going to return the children as well the same value and I'm going to add some styling for the Shadow and so now this looks like a complete mess but I'm going to change that very easily by specifying first of all that the word should be in position relative and the shadow inside of it should be in position absolute and it should also have an opacity of maybe 0.3 and so now we have something like this and I'm going to reduce that even more to maybe 0.1 and if we try this we have a nice animation word by word on scroll so that's pretty nice and now I'm going to take this even further by doing a character by character and so it's going to basically be the same concept but I'm going to add a layer of complexity splitting the word into characters and so I'll go inside of the page.js and I'll import character from the components here have the character and I give the value same thing and then I'll just copy paste the word component and put it inside of the paragraph component and we should have the same thing and the structure here that we have is actually perfect I'm just going to remove the animation from the word because I don't want to be animating the word anymore but more the character and so I remove everything here and I will also remove the shadow concept because we'll create a shadow inside of the character component so I'll remove that and here I'm going to have the characters to be equal to the children and I'm going to split it and so now we have an array for each characters of each word and I can have the characters here I'm going to map them have the character and the index here and I'm going to return a character component and so I'm just going to create it here and also I'll put the character as the children here and so now we have the children and here I can return a span that will be equal to the children add the key to the character and we should have the same thing but now if we look inside of each word we have a span for each character and that's perfect to animate them individually and so now it's the same concept I need to figure out a range for each character and so the first thing that I can create here is an amount and it's going to be equal to the range of a word and so this is the end value here and this is the start value and so we can extract an amount and so I'm going to keep the logs here it's going to be easier to explain and so for example the first word will have an amount of about 4.1% or 0.04 and that amount should be the same for every single word right because it's it's a constant value depending on the length of the paragraph and so after that what I can do is create a step which is going to be very easy it's going to be the amount divided by the length of the word and so we can understand that the first character will have a range of 0 to 0.2 and then the second character will have a range of 0. 2 to 0.4 right approximately and so I'm going to go here and create a new start value for the character and it's going to be equal to the start of the word plus the step multiplied by the index and the end it's going to be the same thing but we're going to multiply by the index + one and I'm going to log them it's going to be easier to understand and so here we have for the first character of the whole paragraph it's going to be animated when the scroll y progress is between 0 and 0.02 and then the second character here will be animated when it's between 0.02 and 0.04 Etc until the end and the last character here will be animated when the scroll progress is between 0.99 and 1 and it's actually really nice because that concept can then be transferred to a power graph of any length and so I'm just going to do the same thing as I did for the word pass down a range and a progress and here it's going to be the progress and then we have the range and the progress for each character and here same thing I have an opacity which is equal to the used transform Hook from for motion and I'm transforming the progress I'm inputting the range and the output that I expect is a value between zero and one and I can put the opacity here as a style I need to put the motion in front of the spawn or else it won't work and let's see if this is working and now we have every single word animated with an opacity and now we just have to recreate the shadow it's going to be the same thing as we did before a span as the parent going to put this one inside and then I'm going to have another span class name sty that shadow and the value will be the children which is the character and if I try this out hell yeah we have the final animation so yeah this is a bit complicated at first to understand but when you wrap your mind around you start to think in the frame or motion way when you do scrolling animation some people really complain about this and they prefer to use Gap because it can abstract a lot of that for you but personally I think it's really nice to understand what's happening there and you can use that same concept for many many other things and so I'll just remove the comments of everything and see the final result I'm going to add some divs here for spacing and I'm going to scroll this and we have the first paragraph which is really simple now looking back and then we have the word by word and then we have the character by character and that's basically the final animation personally I think I prefer the word by word it's less complicated but it's not a question of complexity it's just the final look personally I think I prefer this one over the character by character but depends really on the feeli that you want to give your website but personally I really like the word by word and so yeah that was uh the final animation I hope you guys enjoyed I hope you guys learned something and if you did leave a like subscribe and I'll see you in the next one bye
Info
Channel: Olivier Larose
Views: 14,365
Rating: undefined out of 5
Keywords:
Id: zqPy1bHUjrg
Channel Id: undefined
Length: 17min 43sec (1063 seconds)
Published: Tue Nov 28 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.