Finding the right parallax mechanic

Finding the right parallax mechanic

Parallax is a well-known animation mechanic. Our design team wanted to implement it in the project “Environment in East Germany” to play on the depth between images. I created this effect with JavaScript, the images get translated in the y-axis when the scroll position gets updated.

// update global y position on scroll event (throttled and raf-animated) 
useScrollPositionRaf({ effect: (props) => { 
    dispatch(setYPosition(props.animatedY)) }, 
    deps: [pageHeight], 
})

Unfortunately, this practice causes issues. First, JavaScript code executing on a scroll event is bad for performance. This is even worse because the effect needs to be updated very regularly to give the impression that images are animated smoothly. Second, since it’s in JavaScript, it will get executed after the document updates, which means there will always be a small delay. The problem worsens when the user scrolls back up because the images first get updated to go down and then the parallax effect gets applied, which makes them go back up. When both updates are happening in the same direction, we can keep this impression of smooth animation, but when they are happening in opposite directions, the jagged effect becomes strong.

I researched other ways to create this animation mechanic, one of the alternatives I tried was React Spring since they have nice-looking examples. Unfortunately, they add quite a lot of constraints (specifying how many “pages” you want to animate…) which might not be a problem in a small demo project, but is harder to put in place in a more complex one, not only does it require major structural change, it also makes it a lot harder to maintain. It also created additional issues, since “Environment in East Germany” also has some elements in a sticky position, which stopped working when using the react-spring library.

I also looked into a few additional libraries, but we started running out of time for this project, so we decided to do the most we can, with the existing technique. We simply reduced the effect's strength on some areas of the website, so that the current issues would not be noticeable, and fine-tuned it for the rest.

This parallax mechanic came back in another project called Shaping Mission. This time, the animation is simpler, since only the SVG shape shown in the header should move at a different speed than the rest of the document. Learning that animating with JavaScript has downsides, I decided to find a solution with CSS. I then discovered that this effect is possible with CSS only thanks to a transformation on the z-axis, which can make an element closer or further away in 3D space. Elements that are closer move faster when scrolling and the ones that are further away move slower. I wrote an article on how to use this technique. It also adds some constraints to the project (the container of the element with the parallax effects must be scrollable…), so it might not be suitable for all use cases, but it worked nicely.