What you'll learn:
useTransform
use-parallax
library.We'll now make our icon "sticky" — sticking to a certain position — when it enters a certain range.
See for yourself! Scroll Effects.
Think about how we would do this.
Usually, when we scroll up, everything on the page will move along with it, so how can we make something stay in position?
By applying a y
offset that is equal and opposite to our scroll, our item will seem like it is staying in position.
To illustrate, if we move up the page by 300 pixels, we simply need to move our icon down by 300 pixels.
Back in our code, we'll create a new MotionValue
called iconY
.
function App() {
const offset = useMotionValue(0)
const iconOpacity = useTransform(offset, [0, -500], [1, 0])
const iconBorderRadius = useTransform(offset, [0, -500], [20, 100])
const iconY = useTransform(offset, [0, -300], [0, 300])
return(
...
)
}
Then in our icon <Frame>
, we'll set y={iconY}
and comment out opacity={iconOpacity}
for now.
<Frame
y={iconY}
opacity={iconOpacity}
backgroundColor="white"
size={200}
top={400}
borderRadius={iconBorderRadius}
center="x"
image="/starship.png"
/>
We can play with the useTransform
numbers to get different effects.
[0, 100]
function App() {
...
const iconY = useTransform(offset, [0, -300], [0, 100])
return(
...
)
}
Since [0, 300]
was the "balance" point so that our icon could stick, a smaller number will cause a net, negative offset to occur. As a result, [0, 100]
creates a net, negative offset in the direction of scrolling.
Our icon moves slower than the page.
function App() {
...
const iconY = useTransform(offset, [0, -300], [0, 500])
return(
...
)
}
We have a net, positive offset. Therefore, our icon will move in the opposite direction we scroll since by scrolling to a negative value, we'll get a positive icon offset.
[0, -100]
function App() {
...
const iconY = useTransform(offset, [0, -300], [0, -100])
return(
...
)
}
With -100
, we have a net negative offset, but this time, the net offset is greater than just our scrolling offset. To illustrate, not only are we scrolling with the icon, but the icon is also giving an additional negative offset. Combined, our icon moves faster than our scroll.
By changing the numbers, we can achieve many different parallax effects.
[0, -150, -300], [0, 50, 200]
Furthermore, we can more than two numbers in the array to create some more effects.
function App() {
...
const iconY = useTransform(offset, [0, -150, -300], [0, 50, 200])
return(
...
)
}
Initially, the icon is moving slower than our scroll then the icon sticks and finally moves with the page.
You can play around with the numbers to achieve the effect you are looking for.
However, sometimes we have to use some math to get our correct movement.
use-parallax
LibraryTo make it easier, I wrote a small library that includes a few useful custom hooks.
Let's add my dependency called use-parallax
.
Let's import a hook.
import "./styles.css"
I wrote usePositiveOffset
because it was a hassle constantly adjusting the useTransform
values and whether they should be negative or positive!
function App() {
const offset = useMotionValue(0)
const pOffset = usePositiveOffset(offset)
...
return(
...
)
}
With usePositiveOffset
we no longer need to worry about the negative values. We can instead use positive numbers in the range as long as our input was initialized with usePositiveOffset
.
function App() {
const offset = useMotionValue(0)
const pOffset = usePositiveOffset(offset)
const iconOpacity = useTransform(offset, [0, -500], [1, 0])
const iconBorderRadius = useTransform(pOffset, [0, 500], [20, 100])
const iconY = useTransform(pOffset, [0, 150, 300], [0, 50, 200])
return(
...
)
}
This works just as before:
I created another hook called useSticky
.
import "./styles.css"
With useSticky
we can replace useTransform
and giving useSticky
a list of ranges where we want our element to be sticky.
function App() {
const offset = useMotionValue(0)
const pOffset = usePositiveOffset(offset)
const iconOpacity = useTransform(offset, [0, -500], [1, 0])
const iconBorderRadius = useTransform(pOffset, [0, 500], [20, 100])
const iconY = useSticky(pOffset, [0, 100], [200, 400], [600, 800])
return(
...
)
}
Remember that we need to use pOffset
inside of useSticky
!
We now have there ranges in which our icon sticks.
Without these custom hooks, it would take some time to re-create these effects. However, I encourage you to try create some of theses effects from scratch as you will gain a deeper understanding of what is happening.
We've now covered how to create a sticky scroll effect and customize a scrolling parallax effect. You should now know the underlying basics behind many of those design effects on popular websites!
If you have trouble with the sticky or parallax effect, remember to use my use-parallax
library! It has a lot of code to help you design!
In the next post, we'll cover some more parallax hooks from my library.