The following code animates an item's Y position based on how much of its parent is currently visible. This is the first time I ever animated something on JavaScript based on the window scroll position and the current performance is extremely bad. I am looking for ways to get this running as fast as possible for a smooth animation.
The code I use to get a percentage between 0 and 100 based on how much an element is currently visible is the following:
const calcVisibilityForElem = (elem) => {
const windowHeight = window.innerHeight;
const docScroll = window.pageYOffset || document.documentElement.scrollTop;
const divPosition = elem.offsetTop;
const divHeight = elem.offsetHeight;
const hiddenBefore = docScroll - divPosition;
const hiddenAfter = divPosition + divHeight - (docScroll + windowHeight);
if (
docScroll > divPosition + divHeight ||
divPosition > docScroll + windowHeight
) {
return 0;
} else {
let result = 100;
if (hiddenBefore > 0) {
result -= hiddenBefore * 100 / divHeight;
}
if (hiddenAfter > 0) {
result -= hiddenAfter * 100 / divHeight;
}
return result;
}
};
The code I use to animate:
const calcVisibilityForAllArticles = () => {
document.querySelectorAll('article').forEach((item) => {
const top = calcVisibilityForElem(item);
if (top !== 0) {
item.querySelector('span').style.transform = `translateY(${Math.floor(
top * 1.5
)}px)`;
}
if (top >= 80) {
const navItem = document.querySelector(`[href="#${item.id}"]`);
document.querySelectorAll('nav a').forEach((navItem) => {
navItem.classList.remove('highlight');
});
navItem.classList.add('highlight');
navItem.focus();
}
});
};
In my process trying to boost its performance I made 2 changes, first of all, I animate using translate in the place of the top position, from what I understand changing any value other than transform causes a window repaint. The other change I made is to only animate elements that are inside my viewport. (top !== 0)
=== Only animate elements that are at least 1% inside the viewport.
I don't think that the code itself is very slow, however, the calcVisibilityForAllArticles function is run by:
document.onscroll = () => {
calcVisibilityForAllArticles();
};
With means that the function is run back to back extremely fast. (With is needed for a smooth animation.)
Any help is more than welcome.