I am interested in setting up an HTML page with multiple video clips such that each video clip plays only while visible and then pauses when out of view.
I have fo
As explained here, the offsetTop/offsetLeft/etc. approaches are slower and more error prone than the newer getBoundingClientRect approach. Here's some working code to play any videos that are even partially visible in the viewport:
function playVisibleVideos() {
document.querySelectorAll("video").forEach(video => elementIsVisible(video) ? video.play() : video.pause());
}
function elementIsVisible(el) {
let rect = el.getBoundingClientRect();
return (rect.bottom >= 0 && rect.right >= 0 && rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerWidth || document.documentElement.clientWidth));
}
let playVisibleVideosTimeout;
window.addEventListener("scroll", () => {
clearTimeout(playVisibleVideosTimeout);
playVisibleVideosTimeout = setTimeout(playVisibleVideos, 100);
});
window.addEventListener("resize", playVisibleVideos);
window.addEventListener("DOMContentLoaded", playVisibleVideos);
The setTimeout stuff ensures that the playVisibleVideos() function isn't called any more often than once every 100ms as the user scrolls (so it doesn't cause lag).
Note that it seems like @Tristanisginger's answer using the more modern IntersectionObserver approach may be a better choice than this one for most people.