Animate CSS Background Position With the useSpring Hook

Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 3 years ago

In this lesson, you'll learn how to implement smooth image scrolling using React Spring's useSpring hook

You will use an onMouseMove event to get the image and mouse coordinates and set useSpring with the offset. You can then style the animated element with the backgroundPositionX and backgroundPositionY CSS properties.

Christian Nwamba: [0:00] The first thing we need to do is to create a state to track where our mouse is. We have XY for the coordinates. We can set these coordinates using the setXY method. This is going to be set to the return value of useState. The default value for our states is going to be set to X, , and Y, at onMouseMove event.

[0:33] The actual element that you want to track is that one. What we can do is get the actual position of the cursor using clientX and clientY from the event payload.

[0:56] We can also find where this box started using left and top properties from getBoundingClient. We can do something like e.target.getBoundingClientRect. What this would give us is the offset from the top and left for this particular element that we have this onMouseMove on.

[1:30] To get the actual x and y position for this cursor and this box, we need to one for x, subtract left from clientX. Secondly for y, subtract top from clientY. Now we can update the state using x and y. We can do setXY to an object x and y.

[2:10] We can use the x and y values to update the background position of this particular box whenever we hover on this box. Let's set style to backgroundPositionX. Since this is going to be in percentage, I'm going to wrap this in template literals. We can do xy.x, then percent. Because this box is 400 by 400, and its dimension is 400 by 400, I need to divide this by 4 to actually be set to the appropriate percentage value.

[2:55] We can do the same thing for backgroundPositionY, but set the value to xy.y. Now, if I head to the browser, and start moving around, you can see that every single time I go to the edge of this box, I would see the other part of the image or the other side of the image.

[3:15] We can see that this doesn't look very smooth, so we're going to use React Spring to make it look smoother. Import animated as well as useSpring from React Spring. Instead of tracking the position of our cursor using useState, we can handle animation state with useSpring as well.

[3:45] Call useSpring, which of course, is going to return some values. It takes in a callback function, and this callback function is going to return a list of all the properties that you want to animate. In this case, we want to animate x, which default is zero, and y, which the default is also zero.

[4:11] Now, useSpring is going to return an array of the properties of the animation properties for the animation values, as well as a function that we're going to use to update x and y. Instead of calling setXY, we can refactor and just call set to update these animation values.

[4:32] Then we can use interpolation to update the value of the animation at every single state. We can do props.x.interpolate, which is a function. This function is basically going to take x as well, and just return the same thing we were setting initially. We can do the same thing for y.

[5:03] Instead of x, we have y, y, and of course, we're interpolating y. Now, we of course update this to y as well. Now, if you head to the browser to test this and hover around, nothing basically happens.

[5:21] This is because we are trying to set animation values on a non-animatable element. To make an element animatable, all you need to do is to take animated in front of it, which is basically why we're importing useSpring from React Spring.

[5:37] Let's reload and hover one more time. You can see that the picture scrolls smoothly to all the edges.

Craig
Craig
~ 3 years ago

Can you please explain the dividing by 4 for the 400 x 400 container?

Lucas Minter
Lucas Minter
~ 3 years ago

@craig, I believe he is using division because it is supposed to be constantly updated. If he hard coded the values, the image wouldn't move. Dividing by 4 splits the 400 x 400 image perfectly. If you were to do a 500 x 500 image, you would divide it by 5. I believe the reason is to get it down to a 100 x 100.

Craig
Craig
~ 3 years ago

got it, thanks!

Markdown supported.
Become a member to join the discussionEnroll Today