Skew scrolling is an easy way to give your website’s design a quick boost. A demo of the project we’re going to create can be seen here, and the source code (along with a starter branch) can be found here. I recommend using the starter branch to follow along.
To get started, in our App.js file we’ll return a main div with class name “App”, which contains a nested div with class name “scroll” that’s mapping over an array of images from Unsplash. This div is the scroll container we’ll be manipulating to create our skew effect.
Next, we’ll import React’s useRef hook in order to “take over” the scrolling process and directly manipulate our scroll container. Create 2 refs — one for our App div and one for our scroll container.
We’ll also need to go to our App.scss (regular CSS works fine as well) to “cancel” the default scroll behavior by making our App div fixed to the viewport and hiding the overflow.
So basically, in this next step we’re grabbing the height of our scroll div through its scrollContainer ref (making sure to add .current to access it), and setting our document body’s height equal to that number of pixels. We’re doing all this inside the useEffect hook because the DOM has to finish loading before we can access scrollContainer.
But there’s one more thing! What if the user changes their browser window size after our content has loaded? Our useEffect hook has no dependencies (the empty array at the end) so it can’t account for this yet. Fortunately there’s a nifty hook we can use called useWindowSize that tells us the current window size at any given moment.
So our next step is to make a folder called “hooks” in our src folder, create a file called useWindowSize.js within it, and add the code from the useWindowSize hook. Let’s then import this hook into our App.js and assign it to a const we’ll call size. We can then add size.height to our useEffect’s dependencies so that the document body’s height is updated every time the window height changes.
Now our document height is matching the height of our scroll container and our app has a scrollbar, but it doesn’t actually scroll anything (remember, our “App” div is fixed to the viewport). To scroll our content and implement the skew effect, we’ll need to add a function.
Let’s start by creating the values our function will reference in a const called skewConfigs.
We can then create a function called skewScrolling to handle both scrolling and skewing our content based on scroll velocity. This involves a bit of math but basically we’re calculating the difference between the current and previous scroll position and adding skew based on that difference (greater difference = faster scrolling, which means more skew). We can then use this calculation to transform our content with translate3d for scrolling (better for performance than translateY because it uses the GPU of our device) and skewY for skewing it vertically.
Almost done! The final step is to add requestAnimationFrame() to our function. This basically lets our browser know we want to animate this effect, so it should apply our transformations frame by frame while continuing to gather scroll data. We’ll also include a requestAnimationFrame() inside another useEffect so that it begins running our animation once the DOM loads.
Our project is now skewing and scrolling smoothly. Feel free to play with the 7.5 number in const skew to increase or decrease the skew effect, or remove the skewY for a simple smooth scrolling effect. Thanks for reading!