Framer Motion useViewportScroll 100% height parallax bug
Framer motion has a great method (useViewportScroll) for creating a parallax scrolling effect. If you want to use framer motion to create a parallax effect, here's how you would do that:
export const MyComponent = () => {
const { scrollYProgress } = useViewportScroll()
return <motion.div style={{ scaleX: scrollYProgress }} />
}
But what if scrollYProgress isn't changing?
I ran into an issue where my component was not updating when trying to use framer-motion for a parallax effect. After debugging framer-motion, I found that it was not updating the scrollYProgress value because "maxYOffset" was set to 0. This special parameter is derived by framer-motion, using the following calculation:
document.body.clientHeight - window.innerHeight
Weird, I thought. My document is _definitely_ scrolling. When I checked document.body.scrollHeight, it looked fine. But why was document.body.clientHeight less than document.body.scrollHeight, especially if scrolling is what I care about?
It turns out it was unhappy with my method for forcing the HTML/CSS to take up 100% of the screen.
html,
body {
height: 100%;
min-height: 100%;
}
In this case, height: 100% is limiting the height of the body element. Visually speaking, it works as expected. But the DOM isn't happy when doing this.
Open your browser console and check the following:
document.body.clientHeight - window.innerHeight <= 0
If this equals true, then your body element is getting cut off and framer-motion is ignoring the updates. That will explain why maxYOffset is set to 0, and why scrollYProgress would not be updating. Once that is fixed, your parallax scroll should be working, buttery smooth.