Search code examples
javascripthtml5-videointersection-observer

Why does HTML5 video autoplay when half in viewport, when threshold is set to 1, using IntersectionObserver?


Using this code to autoplay a series of videos, depending on if they are in the viewport:

/**AUTOPLAY VIDEO IN VIEWPORT**/

function playPauseVideo() {
    let videos = document.querySelectorAll("video");
    videos.forEach((video) => {
        // We can only control playback without insteraction if video is mute
        video.muted = true;
        // Play is a promise so we need to check we have it
        let playPromise = video.play();
        if (playPromise !== undefined) {
            playPromise.then((_) => {
                let observer = new IntersectionObserver(
                    (entries) => {
                        entries.forEach((entry) => {
                            if (
                                entry.intersectionRatio !== 1 &&
                                !video.paused
                            ) {
                                video.pause();
                            } else if (video.paused) {
                                /*setTimeout(function() {
                                  video.play();
                                }, 5000);*/
                                video.play();
                            }
                        });
                    },
                    { threshold: 1}
                );
                observer.observe(video);
            });
        }
    });
}

// And you would kick this off where appropriate with:
playPauseVideo();

I'm trying to understand why, when I scroll the video into view it plays as expected, but if the video is finished and I begin to scroll further the video will start again even if it is only partly in the viewport. I want the video(s) to stay paused/stopped until it is completely back into the viewport. The threshold for IntersectionObserver is set to 1 - so this behaviour is confusing me. Any ideas?


Solution

  • You are making it too complicated. you don't need to check audio.play() as it will play the videos unnecessarily.

    here is how I would code it:

    function handleIntersection(entries) {
      entries.forEach(entry => {
        const video = entry.target;
    
        if (entry.isIntersecting) {
          video.play();
        } else {
          video.pause();
        }
      });
    }
    
    const observer = new IntersectionObserver(handleIntersection, {
      threshold: 1.0
    });
    
    const videos = document.querySelectorAll('.video');
    
    videos.forEach(video => {
      observer.observe(video);
    });