intersectionObserver callback called outside threshold

3k views Asked by At

Trying to understand a quirk in intersectionObserver API.

If an observed element is partially on screen but has not met the threshold defined in the options I would expect the call back not to fire, but it does. Trying to understand why or how to prevent it on page load.

function handleIntersect(entries, observer) {
  entries.forEach(function(entry) {
    if (entry.isIntersecting) {
      // Should only fire at >= 0.8
      console.log(entry, entry.intersectionRatio);
      entry.target.classList.add('play');
    }
  });
}

function createObserver(element) {
  let observer;

  const options = {
    threshold: [0.8]
  };

  observer = new IntersectionObserver(handleIntersect, options);
  observer.observe(element);
}

const waypoints = document.querySelectorAll('.section');

waypoints.forEach(waypoint => {
  createObserver(waypoint); 
});

Reduced test case: https://codepen.io/WithAnEs/pen/gxZPMK

Notice how the first 2 sections are animated in even though the second section does not meet the 0.8 threshold (console log). The first inclination is to add an intersectionRatio > 0.8 check, but this is a duplicate effort. Also, the ratio reporting is delayed so could be inaccurate enough not to pass this check.

1

There are 1 answers

3
dizel3d On

isIntersecting doesn't depend on thresholds. It is true, if target element touches or intersects root element. So it's always true if intersectionRatio > 0.

If an observed element is partially on screen but has not met the threshold defined in the options I would expect the call back not to fire, but it does.

Generally, callback is called when condition intersectionRatio >= your_threshold is changed. Therefore it can be called with any intersectionRatio value.

Moreover, it's always called initially.

Also pay attention that 0.8 is just your desired threshold, but observer.thresholds[0] is actual. Without going into details, they could be different a bit, e.g. in Chrome.