I am trying to animate elements while scrolling based on the elements progress through the scene. I am running into the issue of the browser returning intermittent scroll positions making it difficult to be exact when starting and stopping element animation.
Minimal example:
Fiddle Fiddle Demo
const tweens = document.querySelectorAll('.tween');
const trigger = document.querySelector('.start');
const triggerRect = trigger.getBoundingClientRect();
let yScroll = window.scrollY;
let yCurrent = yScroll;
let AF = null;
const start = triggerRect.top - yScroll - 200;
const end = start + 400;
const updateScroll = () => {
yScroll = window.scrollY;
startAnimation();
}
const startAnimation = () => {
if(!AF) AF = requestAnimationFrame(animate)
}
const cancelAnimation = () => {
yCurrent = yScroll;
cancelAnimationFrame(AF);
AF = null;
}
const animate = () => {
if(yCurrent === yScroll) cancelAnimation();
else {
updateElements();
yCurrent = yScroll;
AF = requestAnimationFrame(animate);
}
}
const updateElements = () => {
const pos = yCurrent - start;
if(inScene()){
tweens[0].style.transform = `translateX(${pos}px)`;
tweens[1].style.transform = `translateY(${pos}px)`;
}
}
const inScene = () => {
return start <= yCurrent && end >= yCurrent ? true : false;
};
window.addEventListener('scroll', updateScroll);
.wrapper{
position:relative;
margin: 100vh 20px;
background: rgb(240,240,240);
height: 900px;
border: 1px solid red;
}
.line{
position:absolute;
left: 0;
width: 100%;
height: 1px;
background: red;
}
.start{
top: 200px;
}
.end{
bottom: 200px;
}
.tween{
position:absolute;
top:200px;
width: 100px;
height: 100px;
background: blue;
}
.left{
left: 0;
}
.right{
right: 0;
}
<h1>Scroll Down</h1>
<div class="wrapper">
<div class="line start trigger"></div>
<div class="line end"></div>
<div class="tween left"></div>
<div class="tween right"></div>
</div>
As you can see the elements are supposed to stop on the lines but when you scroll they never really do. And the faster you scroll the worse it becomes.
So is there a technique to either return the correct scroll position or somehow debounce the elements so then can reach the full range when scrolling instead of constantly coming up short of their intended position?
I know this is possible because scrolling libraries like ScrollMagic do a pretty good job of handling this but I don't really want to deconstruct then entire ScrollMagic framework to find out how they achieve it. I would use the ScrollMagic framework itself but I am trying to have a momentum style scrolling container wrapping the page and translating it on scroll along with elements inside this container and using ScrollMagic it is pretty buggy. So I figured I would post the question here and see if anyone had any experience or insight on the situation.
Any guidance would be appreciated as I have been mulling over this for a while.