If you're tired of writing lengthy code to check if an element is in the viewport, consider using an IntersectionObserver instead (much easier). https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
const animateElementRTL = Array.from(document.querySelectorAll('.animateRTL'));
const animateElementLTR = Array.from(document.querySelectorAll('.animateLTR'));
const animateOnEntry = (entries, observer) => {
entries.forEach((entry) => {
if (entry.intersectionRatio === 0) {
// out of viewport, stop animation
if (entry.target.classList.contains('animateRTL')) {
entry.target.classList.remove('resetXRTL');
} else {
entry.target.classList.remove('resetXLTR');
}
} else if (entry.intersectionRatio === 1) {
// fully visible in viewport, start animation
if (entry.target.classList.contains('animateRTL')) {
entry.target.classList.add('resetXRTL');
} else {
entry.target.classList.add('resetXLTR');
}
}
});
}
const rtlObservers = animateElementRTL.map((elem) => {
const observer = new IntersectionObserver(animateOnEntry, {
root: null,
rootMargin: "0px",
threshold: [0, 1]
});
observer.observe(elem);
return observer;
});
const ltrObservers = animateElementLTR.map((elem) => {
const observer = new IntersectionObserver(animateOnEntry, {
root: null,
rootMargin: "0px",
threshold: [0, 1]
});
observer.observe(elem);
return observer;
});
Edit: To create a 'stepped' CSS animation like what you're seeing, use the `threshold` array and `rootMargin` property in the `IntersectionObserver` options object.
For instance, you can step the animation based on the element's visibility percentage on the screen by:
const rtlObservers = animateElementRTL.map((elem) => {
const observer = new IntersectionObserver(animateOnEntry, {
root: null,
rootMargin: "0px",
threshold: [0, 0.2, 0.5, 0.8, 1]
});
observer.observe(elem);
return observer;
});
This will trigger an intersection event, allowing you to apply different CSS classes based on the `intersectionRatio` values at 0, 0.2, 0.5, 0.8, 1.
You could also adjust the starting point of these events beyond the viewport edge by setting a root margin (e.g., a root margin of `2em, 0, 2em, 0` would shift the thresholds calculation starting from 2em (32px) inward from the top and bottom viewport edges).