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.
None of the above seemed to work for me, but I finally found a way: you'll need the visible plugin, and this little piece of code right here:
$(window).scroll(function() {
$('video').each(function() {
if ($(this).visible(true)) {
$(this)[0].play();
} else {
$(this)[0].pause();
}
})
});
This will allow any video to play only when it gets into viewport. By replacing visible( true )
by visible()
, you can set it to play only when the entire video DOM element is in viewport.
This is how I managed to play a video only when the user scrolls to it. I used IsInViewport plugin. Hope you find it useful!
$(window).scroll(function() {
var video = $('.yourvideo');
$(video).each(function(){
if(video.is(':in-viewport')){
video[0].play();
video.removeClass('yourvideo');
//I removed class to stop repeating the action ".play()" when it is scrolled again.
}
});
});
OK, I think, it must be something like this:
var videos = document.getElementsByTagName("video");
function checkScroll() {
var fraction = 0.8; // Play when 80% of the player is visible.
for(var i = 0; i < videos.length; i++) {
var video = videos[i];
var x = video.offsetLeft, y = video.offsetTop, w = video.offsetWidth, h = video.offsetHeight, r = x + w, //right
b = y + h, //bottom
visibleX, visibleY, visible;
visibleX = Math.max(0, Math.min(w, window.pageXOffset + window.innerWidth - x, r - window.pageXOffset));
visibleY = Math.max(0, Math.min(h, window.pageYOffset + window.innerHeight - y, b - window.pageYOffset));
visible = visibleX * visibleY / (w * h);
if (visible > fraction) {
video.play();
} else {
video.pause();
}
}
}
window.addEventListener('scroll', checkScroll, false);
window.addEventListener('resize', checkScroll, false);
Need to check if the video is visible during the scrolling.
$(window).scroll(function() {
$('video').each(function(){
if ($(this).is(":in-viewport")) {
$(this)[0].play();
} else {
$(this)[0].pause();
}
})
});