Around sixteen months ago, we took a look at the Intersection Observer API. The API provides a native means of tracking when elements intersect with a predefined viewport, instead of relying on JavaScript to do the work. This has proved useful in a variety of ways, and the API has been (or soon will be) adopted by most browsers.

Although the API has been a success, there are some proposed updates on the horizon – an Intersection Observer v2. The Chrome team has already started shipping these changes behind a flag, and discussions with other browsers are underway.

So what are these proposed changes? and how will they work? That’s what this post will explore.

Current shortcomings

First, why the need for updates?

In the explainer document for the proposed updates, some shortcomings were identified. Although the current version of the API (v1) tracks when an element intersects with the designated viewport, it doesn’t provide the following information about the element:

  • If it is covered up by something else on the page.

  • If it has any visual effects applied to it (like filters or opacity) that may be affecting its visibility or position.

Even if you know that the element is on the page, you have no way of being sure the element is actually visible to the user.

The main concern that has surfaced is how this kind of knowledge could be helpful in preventing clickjacking and UI redress attacks. Thomas Steiner explores some of these reasons, and much more, in a recent article on the proposed updates to the API. (There is also a related demo showing the potential use cases.)

New properties

IntersectionObserver

To address these shortcomings, the proposed updates include a new configuration property trackVisibility in the IntersectionObserver constructor. If this is set to true, the observer will track changes to the target’s visibility.

The constructor will also have another property called delay, which will allow specifying the delay (in milliseconds) between notifications for a given target. For performance reasons, if trackVisibility is true, the delay value must be set to 100 (ms) or greater.

// Example observer constructor

const observer = new IntersectionObserver(
  (entries) => {
    // Callback function ...
  }, {
    threshold: [1.0],
    trackVisibility: true, // NEW
    delay: 100 // NEW
  }
);

IntersectionObserverEntry

The IntersectionObserverEntry also has a new property called isVisible. If the observer was set to track visibility, and the entry passes the visibility algorithm, this will be set to true. Whenever this is true, it’s a guarantee by the browser that the element is truly visible on the page. You can be confident it’s neither covered up nor visually altered.

// Example callback

entries.forEach(entry => {
  // Can check for visibility with `isVisible`
  if (entry.isIntersecting && entry.isVisible) {
    // Do something ...
  }
});

False negatives

Since the visibility of elements is more expensive to calculate than the intersection of elements, some aspects of the updates have been designed to prevent potential performance degradation.

The delay property mentioned earlier, for instance, has to be set to at least 100ms if the checkVisibility option is true. This ensures that the observer has time between notifications to determine the visibility of its targets.

The spec also explicitly allows for false negatives. Meaning, even if isVisible is set to false, it’s still possible the element may be “visible” onscreen. The visibility algorithm is conservative in declaring an element as ‘visible’, and if there’s any chance that it may not be, it will return false.

For instance, if one of the following is true for the target or its containing block chain, the algorithm will immediately return false:

  • It has an opacity of anything other than 1.0 (even .99).
  • It has any kind of filter applied to it.

If the browser is unable to guarantee the visibility of the element, for whatever reason, it defaults to false.

Which means, if it returns true, you have a solid guarantee by the browser that the element is visible. False positives are not allowed. So if it says something is visible, you know it really is.

Current status

It is still early in the process, and Chrome is the only one to start shipping the updates. Currently, they are behind a flag, so you would need to run Chrome with the flag

--enable-blink-features=IntersectionObserverV2

to see test it out.

[Note: The Chromium project site has instructions for using Chrome (and Chromium) with flags].

Useful when needed

Although useful in some situations, the v2 updates to Intersection Observer do come at a computational cost. This cost may make sense in some situations, where it’s vital to guarantee that an element is visible on the page. But the updates were not intended to be used by everyone for everything. So if you do use the new features in the future, do so only in those situations that truly merit their use.

Further reading

If you’re interested in the v2 updates, here are documents and articles worth taking a look at.