Original address: css-tricks.com/an-explanat… Written by Travis Almand translated by Hui Liu

There have been many excellent articles on using the Intersection Observer API, including Phil Hawksworth, Preethi, and Mateusz Rybczonek. I’m going to talk about something different in this article. I had the pleasure of introducing the VueJS transition component to the Dallas VueJS gathering earlier this year, and my first csS-Tricks article was based on it. During the Q&A portion of my talk, I was asked about triggering transitions based on rolling events — I said sure, but some in the audience suggested I check out the Intersection Observer.

It got me thinking. I have a basic understanding of Intersection Observer and can use it to complete simple examples. Do I know how it works and not just use it? What does it really offer us developers? As a veteran developer, how do I explain how it works to new developers who don’t even know it exists?

After spending some time researching, testing and verifying, I decided to share what I learned.

Intersection computes the Observer is briefly

The Intersection Observer API is described in the W3C Public Work Draft Summary (the first draft, dated September 14, 2017) as:

This specification describes an API for understanding the visibility and position of DOM elements (targets) relative to containing elements or top-level viewports (root). This location is passed asynchronously and is useful for understanding the visibility of elements and for pre-loading and lazy loading of DOM content.

The overall idea of this API is to provide a way to observe a child element and be notified when it enters a bounding box of one of its parents. The target element is most commonly used when scrolling into the root element view. Prior to the introduction of Intersection Observer, such functionality was accomplished by listening for rolling events.

While Intersection Observer is a solution to higher performance for such functions, I don’t suggest we see it as a replacement for rolling events. Instead, I suggest we consider this API as an additional tool that complements the functionality of scrolling events. In some cases, the two can work together to solve a particular problem.

Basic example

I know I’ll probably repeat what I’ve already done in other articles, but let’s first look at a basic example of Intersection Observer and the capabilities it provides.

The Observer consists of four parts:

  1. rootIs the parent element to which the observer is bound, which can be a viewport
  2. target, it is the child element being observed, and there can be more than one
  3. optionsObject that defines some aspect of the observer’s behavior
  4. Callback function that is called each time a change in the intersection of parent and child elements is observed

The code for the basic example looks like this:

const options = {
  root: document.body,
  rootMargin: '0px'.threshold: 0
}

function callback (entries, observer) {
  console.log(observer);

  entries.forEach(entry= > {
    console.log(entry);
  });
}

let observer = new IntersectionObserver(callback, options);
observer.observe(targetElement);

Copy the code

The first part of the code is the Options object, which has the root, rootMargin, and Threshold properties.

Root is the parent element, typically an element with a scrollbar that contains the element being observed. Depending on your needs, this can be almost any single element on the page. If the property is not provided, or if the value is set to NULL, the trailing element is a viewport.

RootMargin describes the margin of the root element, and each side of the rectangle specified by rootMargin is added to the corresponding edge of the root element’s bounding box. It behaves much like the CSS Margin property. You can use something like 10px 15px 20px, which gives us a top margin of 10px, a left and right margin of 15px, and a bottom margin of 20px. Only bounding boxes are affected, not the elements themselves. Keep in mind that the only lengths allowed are pixel and percentage values, which can be negative or positive. Also note that rootMargin is invalid if the root element is not an actual element on the page (such as viewport).

Threshold is a value used to determine when an intersection change event is triggered. An array can contain multiple values so that the intersection change event can be triggered multiple times by the same target. The different values are using percentages from 0 to 1, much like opacity in CSS, so consider a value of 0.5 as 50%, and so on. These values are related to the cross scale of the target, which will be explained later. When the threshold is 0, the intersection change event is triggered when the first pixel of the target element intersects the root element. A threshold of 1 triggers the intersection change event only when the entire target element is inside the root element.

The second part of the code is the callback function, which is called whenever an intersection change is observed. Two arguments are passed; Entries are an array representing each target element that triggers an intersection change. This provides a lot of information for developers to use. The second parameter is information about the observer itself. If the target is bound to multiple observers, you can identify which observer by this parameter.

The third part of the code is the creation of the observer itself and the object to observe. When creating an observer, the callback function and options object can be placed outside the observer. If desired, the same callback and options objects can be used across multiple observers. Then, pass the target element that you want to observe to the observe() method. It can only accept one target, but the method can be called repeatedly for multiple targets on the same observer.

Notice console.log in the code to see what the console outputs.

Observer object

The observer data passed to the callback function is as follows:

IntersectionObserver
  root: null
  rootMargin: "0px 0px 0px 0px"
  thresholds: Array [ 0 ]
  <prototype>: IntersectionObserverPrototype { }

Copy the code

. Essentially the selected Options object passed to the observer when the object is created. This can be used to determine the root element to which the intersection is bound. Note that even though the original option object had a rootMargin value of 0px, the object changed it to 0px 0px 0px 0px, which is required by the CSS margin specification. Then there is the set of thresholds that the observer is using.

The entry object

The entry object data passed to the callback function is as follows:

IntersectionObserverEntry
  boundingClientRect: DOMRect
    bottom: 923.3999938964844.top: 771
    height: 152.39999389648438.width: 411
    left: 9.right: 420
    x: 9.y: 771
    <prototype>: DOMRectPrototype { }
  intersectionRatio: 0
  intersectionRect: DOMRect
    bottom: 0.top: 0
    height: 0.width: 0
    left: 0.right: 0
    x: 0.y: 0
    <prototype>: DOMRectPrototype { }
  isIntersecting: false
  rootBounds: null
  target: <div class="item">
  time: 522
  <prototype>: IntersectionObserverEntryPrototype { }

Copy the code

As you can see, a lot of work has been done here.

The two most likely to be useful to most developers are intersectionRatio and isIntersecting. The isIntersecting attribute is a Boolean value that determines whether the target element intersects the root element when the intersection changes. IntersectionRatio is the percentage of target elements that currently intersect the root element. It is also a percentage representation between zero and one, much like threshold in the options object of the observer.

The three attributes (boundingClientRect, intersectionRect, and rootBounds) represent specific data for the three intersection-related aspects. BoundingClientRect properties for the boundary of the target Element box, starting from the left upper corner of the viewport of bottom, left, right and top value, like Element. GetBoundingClientRect (). The height and width of the target element are then supplied as X and Y coordinates. The rootBounds property provides the same form of data for the root element. IntersectionRect provides similar data, which describes the rectangle formed by intersecting area of target element inside the root element, and this area is also used to calculate intersectionRatio value. Traditional scrolling events require this calculation to be done manually.

Note that all of these shapes representing these different elements are always rectangles. Regardless of the actual shape of the element involved, they always shrink to the smallest rectangle containing the element.

The target attribute refers to the target element being observed. In cases where the observer contains multiple targets, this is an easy way to determine which target element triggered this intersection change.

The time property provides the time, in milliseconds, between the first observer creation and the triggering of this intersection change. That way, you can track how long it takes viewers to meet a particular target. This property provides a new time even if the target is later scrolled into the view again. This can be used to track when the target enters and leaves the root element.

In addition to getting this information every time we observe an intersection change, the observer also gives us this information the first time it’s activated. For example, when the page loads, the observer on the page will immediately invoke the callback function and provide the current state of each target element it is observing.

The Intersection Observer provides data about the relationships between elements on a page in a very efficient way.

The methods available to the Intersection Observer

Intersection Observer has three main methods: observe(), unobserve(), and disconnect().

  • Observe () : The observe method is used to add a target element that the observer wants to monitor. An observer can have multiple target elements, but this method can only accept one target at a time.
  • Unobserve () : The unobserve method is used to remove elements from the list of unobserved elements.
  • Disconnect () : The disconnect method is used to stop viewing all its target elements. The observer itself is still active, but has no target. After disconnect(), the target element can still be passed to the observer via Observe ().

These methods provide the ability to monitor and unmonitor target elements, but once created, there is no way to change the Options object passed to the observer. If you need to modify, you must manually recreate the observer.

Performance comparison of the Intersection Observer and rolling events

I needed to do some performance testing while exploring the Intersection Observer and comparing it to using rolling events. I just wanted to get a rough idea of the performance differences between the two, so I created three simple tests to do that.

First, I created a sample HTML file with a hundred divs set to height to create a long scrolling page. Placing the page on a static server, I then load the HTML file with Puppeteer, start the trace, scroll the page down to the bottom in preset increments, stop the trace once I reach the bottom, and finally save the trace results. This allows the test to be repeated multiple times and output the resulting data each time. I then copied the sample HTML and wrote JS in the script tag for each type of test I wanted to run. Each test has two files: one for the Intersection Observer and one for rolling events.

The purpose of all tests is to detect when the target element scrolls up through the viewport in a 25% increment. With each increment, a CSS class is applied to change the background color of the element. In other words, DOM modifications are applied to each element, which triggers a redraw. Each test ran five times on two different computers: my development Mac was the latest device, and my personal Windows 7 computer was probably the current average. Record the tracking results of scripts, renders, paintings, and systems, and then average them.

The first test has either an observer or a scroll event, each with a callback. This is a fairly standard setup for observer and scroll events. In this case, though, scroll events have a lot of work to do, because scroll events attempt to mimic the data provided by the observer by default. After all of these calculations are done, the data is stored in an array of items, just like an observer. Then, deleting and applying classes between the two functions exactly the same. I also throttled the scrolling event using requestAnimationFrame.

The second test had 100 observers or 100 scroll events, with a callback for each type. Each element is assigned its own observer and event, but the callback function is the same. This is actually inefficient because every observer and event behaves exactly the same, but I wanted a simple stress test without having to create 100 unique observers and events – although I’ve seen many examples of observers being used this way.

The third test had 100 observers or 100 scroll events, with 100 callbacks for each type. This means that each element has its own observer, event, and callback functions. Of course, this is extremely inefficient, because it’s all repetitive functionality stored in a huge array. But this inefficiency is the focus of the test.

In the diagram above, you can see that the first column, which represents our benchmark, is not running JavaScript at all. The next two columns represent the first test type. The Mac all worked very well, as I’d expect from a high-end computer for development. Windows machines give us a different result. For me, the main point of interest is the script represented by red. On a Mac, the difference was about 88 milliseconds for the observer and 300 milliseconds for the scroll event. On Mac, the overall results for each test were pretty close, but the script did a good job of rolling events. For Windows machines, it’s much worse. The observer was about 150 milliseconds, while the first and simplest test was about 1400 milliseconds.

For the second test, we started to see the efficiency of rolling tests become more apparent. The Observer tests were run on both Mac and Windows machines, and the results were almost the same as before. With the rolling event test, the script gets into more trouble and fails to complete the given task. Macs jump to almost a full second of scripting time, while Windows computers jump to a whopping 3200ms.

For the third test, it didn’t get any worse. The results were roughly the same as in the second test. One thing to note is that in all three tests, the observer’s results were consistent for both computers. Although no optimizations have been made to make Observer testing more efficient, Intersection Observer performance far outperforms rolling events.

So, after non-scientific testing on two of my own machines, I felt I had a good understanding of the performance differences between rolling events and the Intersection Observer. I’m sure I could make scrolling events more efficient with some effort, but is it worth it? In some cases, the precision of rolling events is necessary, but in most cases, the Intersection Observer is sufficient — especially since it appears to be more efficient without requiring any effort.

Clarify intersectionRatio properties

IntersectionObserverEntry provide us intersectionRatio attributes, represents the target elements in the intersection the percentage of change within the root element on the boundary. I realized that I didn’t quite understand what this value actually meant at first. For some reason, I think this is a simple 0% to 100% representation of the appearance of the target element. It is related to the threshold passed to the observer at creation time. For example, it can be used to determine which threshold was the cause of the intersection change that was just triggered. However, the values it provides are not always simple.

Take this demo as an example:

demo

In this demo, the observer has been assigned the parent container as the root element. Child elements with target backgrounds are assigned as target elements. An array of thresholds has been created that contains 100 entries in the order 0, 0.01, 0.02, 0.03, and so on up to 1. The observer triggers each percentage of the target element that appears or disappears within the root element so that the output text below this box is updated whenever the ratio changes by at least one percent. If you are curious, you can accomplish this threshold with the following code:

[...Array(100).keys()].map(x= > x / 100)}Copy the code

I do not recommend that you set thresholds in this way for specific uses in your project.

First, the target element is completely contained in the root element, and the output above the button shows the ratio 1. It should be the first time it’s loaded, but as we’ll soon find out, that ratio isn’t always accurate; The number could be between 0.99 and 1. This may seem strange, but it can happen, so keep this in mind if you’re checking for ratios equal to certain values.

Clicking the “Left” button converts the target element to the left so that half of it is in the root element and the other half is not. Then, the ratioRatio should be changed to 0.5, or close to 0.5. Now we know that half of the target element intersects the root element, but we don’t know where it is. More on that later.

Clicking the “Top” button has the same function. It converts the target element to the top of the root element and moves it in and out again. Again, the intersection ratio should be around 0.5. Even if the target element is in a completely different location than before, the resulting ratio is the same.

Clicking the “Corner” button again converts the target element to the upper right corner of the root element. At this point, only a quarter of the target elements are inside the root element. IntersectionRatio should be reflected at about 0.25. Clicking Center converts the target element back to the center and is fully included in the root element.

If you click the “Large” button, change the height of the target element to higher than the root element. The intersection ratio should be about 0.8. This is the tricky part of relying on intersectionRatio. Creating code based on the threshold provided to the observer makes it so that the threshold never fires. In this “Large” example, any code based on threshold 1 will not execute. Also consider situations where you can resize the root element, such as rotating the viewport from portrait to landscape.

To find the location

So how do we know where the target element is relative to the root element? This data is provided by IntersectionObserverEntry, so we only need to simple comparison.

Look at the demo:

demo2

The setup for this demo is much the same as the previous setup. The parent container is the root element, and the child container with the target background inside is the target element. The threshold is an array of 0, 0.5, and 1. As you scroll through the root element, the target appears and its position is reported in the output above the button.

The following code performs these checks:

const output = document.querySelector('#output pre');

function io_callback (entries) {
  const ratio = entries[0].intersectionRatio;
  const boundingRect = entries[0].boundingClientRect;
  const intersectionRect = entries[0].intersectionRect;

  if (ratio === 0) {
    output.innerText = 'outside';
  } else if (ratio < 1) {
    if (boundingRect.top < intersectionRect.top) {
      output.innerText = 'on the top';
    } else {
      output.innerText = 'on the bottom'; }}else {
    output.innerText = 'inside'; }}Copy the code

I should point out that I didn’t iterate through the Entrys array because I knew there was always only one entry because there was only one target. I took a shortcut and used entries[0].

You’ll find that a ratio of zero puts the target “outside.” Ratios less than 1 place them at the top or bottom. This way, we can see if the “top” of the target is smaller than the top of the intersection rectangle, which in effect means that the target is taller on the page and is considered “top.” In fact, checking the “top” of the root element also solves this problem. Logically, if the target is not at the top, it must be at the bottom. If the ratio is exactly 1, it is “inside” the root element. The horizontal position is checked the same way except with the left or right attribute.

This is part of using Intersection Observer effectively. The developer does not need to request this data from multiple locations on a throttled rolling event and then compute it. It is provided by the observer and all that is required is a simple if check.

First, the target element is taller than the root element, so it is never reported as “internal.” Click the Toggle Target Size button to make it smaller than the root. The target element can now be inside the root element when scrolling up and down.

Restore the target element to its original size by clicking “Toggle Target Size” again and then clicking the “Toggle Root Size” button. This will resize the root element to be higher than the target element. Again, when scrolling up and down, the target element may be inside the root element.

This demo demonstrates two things about the Intersection Observer: how to determine the position of the target element relative to the root element and what happens when you resize two elements. This response to resizing gives the Intersection Observer another advantage over rolling events — it no longer has to handle resize events alone.

Create location stickiness events

The “sticky” feature of the CSS position property is a useful feature, but has some limitations with regard to CSS and JavaScript. The style of a viscous node can only be one design, either in its normal state or in its viscous state. There is no way to let JS know about these changes. So far, there are no pseudo-class or JS events that let us know about state changes of elements.

I’ve seen examples of using scroll events and the Intersection Observer for sticky positioning events. Solutions that use rolling events always have similar problems as using rolling events for other purposes. A common solution for observers is to have a positioning element that is used only as the target element of the observer. I like to avoid single-purpose elements like this, so I decided to modify this particular idea.

In this demo, scroll up and down to see the sticky reactions of chapter titles to their respective chapters.

demo3

This example detects when a sticky element is at the top of a scrolling container and then adds a CSS class to it. This is done by taking advantage of an interesting feature of the DOM when giving an observer specific rootMargin. The values given are:

rootMargin: '0px 0px -100% 0px'
Copy the code

This pushes the bottom edge of the root boundary to the top of the root element, leaving a small area of zero pixels available for intersection detection. It can be said that the intersection change is triggered even if the target element touches the zero pixel region, even if it does not exist in a number. Consider that we can have elements in the DOM that fold to zero height.

The solution takes advantage of this by identifying the “sticky” position where the sticky element is always at the top of the root element. As the scroll continues, the viscous elements eventually move out of view and the intersection stops. Therefore, we add and delete classes based on the isIntersecting property of the input object.

Here is the HTML:

<section>
  <div class="sticky-container">
    <div class="sticky-content">
      <span>&sect;</span>
      <h2>Section 1</h2>
    </div>
  </div>

  {{ content here }}

</section>

Copy the code

The external div with class sticky- Container is the target of the observer. The div will be set to be a sticky element and act as a container. The elements used to style and change elements based on sticky state are div with sticky- Content class and its child elements. This ensures that the actual sticky element always touches the narrowed rootMargin at the top of the root element.

Here is the CSS:

.sticky-content {
  position: relative;
  transition: 0.25 s;
}

.sticky-content span {
  display: inline-block;
  font-size: 20px;
  opacity: 0;
  overflow: hidden;
  transition: 0.25 s;
  width: 0;
}

.sticky-content h2 {
  display: inline-block;
}

.sticky-container {
  position: sticky;
  top: 0;
}

.sticky-container.active .sticky-content {
  background-color: rgba(0, 0, 0, 0.8);
  color: #fff;
  padding: 10px;
}

.sticky-container.active .sticky-content span {
  opacity: 1;
  transition: 0.25 s 0.5 s;
  width: 20px;
}
Copy the code

You can see that. Sticky -container creates our sticky element at top 0. The rest is a mixture of the regular state in.sticky- Content and the sticky state style in.active.sticky – Content. Similarly, you can do almost anything you want in a sticky content div. In this demo, when the sticky state is active, a hidden chapter symbol appears in the delayed transition. This effect is difficult to achieve without auxiliary means such as Intersection Observer.

JavaScript:

const stickyContainers = document.querySelectorAll('.sticky-container');
const io_options = {
  root: document.body,
  rootMargin: '0px 0px -100% 0px'.threshold: 0
};
const io_observer = new IntersectionObserver(io_callback, io_options);

stickyContainers.forEach(element= > {
  io_observer.observe(element);
});

function io_callback (entries, observer) {
  entries.forEach(entry= > {
    entry.target.classList.toggle('active', entry.isIntersecting);
  });
}
Copy the code

This is actually a very simple example of using the Intersection Observer to accomplish this task. The only exception is the -100% value in rootMargin. Note that this can be repeated for the other three; It only requires a new observer with its own unique rootMargin, which has a value of -100% for the corresponding aspect. There will be more unique sticky containers with their own classes, such as sticky-container-top and sticky-container-bottom.

The limitation of this is that the top, right, bottom, or left attribute of the sticky element must always be zero. Technically, you can use other values, but then you have to do the math to figure out the correct value for rootMargin. This is easy to do, but if you resize, you not only have to do the math again, you have to stop the observer and restart it with the new value. It is easier to set the position property to zero and use the inner element to set the style the way you want.

Combined with a rolling event

So far, we have seen in some demonstrations that intersectionRatio may be inaccurate and somewhat limited. Using scrolling events can be more precise, but can reduce the efficiency of performance. How about combining the two?

demo4

In this demo, we create a Intersection Observer, and the callback function’s sole purpose is to add and remove event listeners that listen for Scroll events on the root element. A scrolling event listener is created when the target first enters the root element, and then deleted when the target leaves the root element. When scrolling, the output simply shows the timestamp of each event to show how the event changed in real time – much more accurate than a single observer.

Here’s JavaScript.

const root = document.querySelector('#root');
const target = document.querySelector('#target');
const output = document.querySelector('#output pre');
const io_options = {
  root: root,
  rootMargin: '0px'.threshold: 0
};
let io_observer;

function scrollingEvents (e) {
  output.innerText = e.timeStamp;
}

function io_callback (entries) {
  if (entries[0].isIntersecting) {
    root.addEventListener('scroll', scrollingEvents);
  } else {
    root.removeEventListener('scroll', scrollingEvents);
    output.innerText = 0;
  }
}

io_observer = new IntersectionObserver(io_callback, io_options);
io_observer.observe(target);
Copy the code

This is a pretty standard example. Note that we want the threshold to be zero, because if there is more than one threshold, we will get multiple event listeners at the same time. The callback function is of interest to us, even as a simple setup: add and remove event listeners in if-else blocks. The event callback only updates the div in the output. Whenever the target triggers an intersection change and does not intersect the root, we set the output back to zero.

This example takes advantage of the Intersection Observer and rolling events. Consider using a scrolling animation library that works only when the part of the page that needs it to be physically visible. Libraries and scroll events are not inactive throughout the page.

Interesting differences in browsers

You might wonder how much browser support Intersection Observer has. Quite a lot, actually!

The browser supports data from Caniuse, more information. Numbers indicate that the browser supports this version and later features.

All major browsers have supported it for some time. As expected, IE does not support it at any level, but the W3C provides a polyfill to address this issue.

When I tried different ideas with the Intersection Observer, I did come across two examples that behaved differently between Firefox and Chrome. I won’t use these examples on production sites, but the behavior is interesting.

Here’s the first example:

example1

The target element is moved within the root element using the CSS Transform attribute. The demo has A CSS animation that moves the target element in and out of the root element on the horizontal axis. IntersectionRatio is updated when the target element enters or leaves the root element.

If you view this demo in Firefox, you should see intersectionRatio updates correctly when you swipe the target element back and forth. Chrome behaves differently and does not update intersectionRatio at all. Chrome does not seem to retain labels for target elements that have been transformed using CSS. However, intersectionRatio does update if we move the mouse around in the browser as the target element moves in and out of the root element. My guess is that Chrome only “activates” the observer when there is some form of user interaction.

Here’s the second example:

example2

This time, we animate a clipping path that turns a square into a circle in a repeating loop. The square has the same size as the root element, so the intersectionRatio we get will always be less than 1. As the tailoring path is animated, Firefox does not update intersectionRatio at all. Moving the mouse doesn’t work this time. Firefox simply ignores changes in element size. Chrome, on the other hand, actually updates the intersectionRatio display in real time. This happens even if there is no user interaction.

This happens because part of the specification states that intersectionRect boundaries should include the tailoring target element.

If the container has an overflow clipping or CSS clipping path attribute, update intersectionRect by applying the clipping of the container.

Therefore, when clipping a target, the boundaries of the intersecting regions are recalculated. Firefox is clearly not there yet.

Intersection Observer, version 2

So what’s the future of the API?

Google offers some suggestions that will add an interesting feature for observers. Even if the Intersection Observer tells us when the target element crosses the boundary of the root element, it doesn’t necessarily mean that the element is actually visible to the user. It may have zero opacity, or it may be overwritten by another element on the page. Can the observer be used to determine these things?

Keep in mind that we are still in the early stages of using this feature, so you should not use it in production code. This is the updated proposal, which highlights the differences from the first version of the specification.

If you’ve been browsing through this demo in Chrome, you’ve probably noticed a few things on the console – such as the missing entries object properties in Firefox. Here’s an example of Firefox printing in the console:

IntersectionObserver
  root: null
  rootMargin: "0px 0px 0px 0px"
  thresholds: Array [ 0 ]
  <prototype>: IntersectionObserverPrototype { }

IntersectionObserverEntry
  boundingClientRect: DOMRect { x: 9.y: 779.width: 707. } intersectionRatio:0
  intersectionRect: DOMRect { x: 0.y: 0.width: 0. } isIntersecting:false
  rootBounds: null
  target: <div class="item">
  time: 261
  <prototype>: IntersectionObserverEntryPrototype { }

Copy the code

Now, here’s the output from the same console code in Chrome:


IntersectionObserver
delay: 500
root: null
rootMargin: "0px 0px 0px 0px"
thresholds: [0]
trackVisibility: true
__proto__: IntersectionObserver

IntersectionObserverEntry
boundingClientRect: DOMRectReadOnly {x: 9.y: 740.width: 914.height: 146.top: 740. } intersectionRatio:0
intersectionRect: DOMRectReadOnly {x: 0.y: 0.width: 0.height: 0.top: 0. } isIntersecting:false
isVisible: false
rootBounds: null
target: div.item
time: 355.6550000066636
__proto__: IntersectionObserverEntry

Copy the code

There are some differences in how some attributes, such as Target and Prototype, are displayed, but they operate the same in both browsers. The difference is that Chrome has some other properties that don’t show up in Firefox. The Observer object has a Boolean value called trackVisibility, a number called delay, and the Entry object has a Boolean value called isVisible. These are the newly proposed attributes that attempt to determine whether the target element is actually visible to the user.

I’ll cover these properties briefly, but if you need more details, please read this article.

The trackVisibility property is a Boolean value provided to the observer in the Options object. This attribute lets the browser take on the task of determining the true visibility of the target element.

Guess what the delay property is for: It delays the intersection change callback method for a specified amount of time in milliseconds. This is somewhat similar to wrapping the code for the callback function in setTimeout. This value is required for trackVisibility to work and must be at least 100. If the appropriate value is not provided, the console displays the error and the observer will not be created.

Uncaught DOMException: Failed to construct 'IntersectionObserver': To enable the
'trackVisibility' option, you must also use a 'delay' option with a value of at
least 100. Visibility is more expensive to compute than the basic intersection;
enabling this option may negatively affect your page's performance.
Please make sure you really need visibility tracking before enabling the
'trackVisibility' option.
Copy the code

The isVisible attribute in the target Entry object is a Boolean value that reports the visibility trace output. It can be used as part of any code, just like isIntersecting.

In all my experiments with these features, I’ve seen it actually work sometimes and sometimes not. For example, the delay is always in effect when the element is clearly visible, but isVisible doesn’t always report true (at least to me). Sometimes this is by design, because the specification does allow for a second type of error. This would help explain the inconsistent results.

I personally can’t wait for this feature to be completed and to work in all browsers that support Intersection Observer.

Write in the last

This is the end of my study of Intersection Observer. I spent many nights researching, experimenting and building examples to understand how it worked. This article covers some new ideas about how to take advantage of the different capabilities of the observer. In addition, I think I can clearly explain how observers work. Hope you found this article helpful.


If you think this article is valuable to you, please like it and pay attention to our official website and WecTeam. We have quality articles every week: