I want to implement slow scrolling. I decided to create a container 10 times larger than its content. The content is then moved via JavaScript, based on scroll events.
The example is in React, but straightforward. I marked this question with the JavaScript tag because the problem I have relates to JavaScript itself, not to React/TypeScript/etc.
'use client'
import { useEffect, useRef, useState } from 'react'
const targetHeight = 100 // container's height
const rootHeight = 10000 // 10x times larger container
export default function FooBar() {
const ref = useRef<HTMLDivElement | null>(null)
useEffect(() => {
function onScroll() {
const scrollTop =
document.documentElement.scrollTop || document.body.scrollTop
const scrollHeight =
document.documentElement.scrollHeight || document.body.scrollHeight
const clientHeight =
document.documentElement.clientHeight || window.innerHeight
const scrollProgress = scrollTop / (scrollHeight - clientHeight) // from 0 to 1
const result = Math.floor((rootHeight - targetHeight) * scrollProgress)
setTop(result)
}
window.addEventListener('scroll', onScroll, { passive: true })
return () => {
window.removeEventListener('scroll', onScroll)
}
}, [])
const [top, setTop] = useState(0)
return (
<div
ref={ref}
style={{
height: rootHeight,
}}
>
<div
style={{
willChange: 'transform',
transform: `translate3d(0, ${top}px, 0)`,
transition: 'width 0s',
}}
>
<div style={{ width: 100, height: 100, background: 'white' }} />
</div>
</div>
)
}
Everything is not complicated. However, when scrolling with a mouse, the animation is jumpy. See the following reproduction:
https://stackblitz.com/edit/stackblitz-starters-fqrzww?file=app%2Fpage.tsx
Try to scroll the example. I expect the white rectangle to move smoothly. However, it’s so jumpy.
I really have no idea what’s the reason of this behavior. The computed values are not "jumpy", they are sequential.
2
Answers
In fact, it used the "transition" property css to be smooth, but put the calculation function outside of "useEffect" and try it.
In fact, you wanted to move the element by subtracting the amount of page scrolling from the amount of scrolling of the entire page, but I manipulated your code a bit and this time I obtained the percentage of the scrolling by calculating the amount of scrolling and by changing the element’s state to floating state, it is good.