I want to implement slow scrolling. I decided to create a relative container 10 times larger than its absolute content. The content is 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={{
position: 'relative',
height: rootHeight,
}}
>
<div
style={{
position: 'absolute',
top,
left: 0,
right: 0,
}}
>
<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.