preface

Imagine a scenario where you want your website to do the following:

  1. Lazy loading of images while the page is scrolling and asynchronous loading of images improves page response times and optimizes UX
  2. Achieve Infinite scrolling, constantly load new resources in a page and add them to the current page, so as to avoid page jump and repeat rendering, Vue, React, etcVDOMThe idea of optimizing UX is similar
  3. When an AD is loaded on a page and the service provider asks for the data, it only counts if the AD enters the user’s view
  4. Render elements or animations depending on whether the user wants to see the results

If you want to implement these functions by yourself, you need to poll in JS to continuously obtain the location information of the target element, and calculate whether the corresponding conditions are met. However, because this polling function is running in V8 main thread, it consumes a lot of resources, and it is very easy to drop frames, bringing a very poor user experience.

Meanwhile, if you have a web page with infinite scrolling, the developer uses a third party library to manage ads throughout the page, another library for message boxes and likes, and a lot of animations. Both libraries have their own intersection detection programs, both run on the main thread, and the developers of the site know little about the internal implementation of these libraries, so they are not aware of any problems. But when the user scrolls the page, these intersecting detection programs will repeatedly trigger calls in the page scroll callback function, causing performance problems and disappointing experience.

Intersection Observer was born to solve this problem.

Intersection Observer

Intersection Observer is a W3C API for the Observer. The Intersection Observer is a globally accessible object in the browser called GO. Because the Observer does not execute in the main thread, resource consumption is reduced and web page performance is optimized.

The Intersection Observer API provides Web developers with the ability to asynchronously query the position of elements relative to other elements or Windows. It is often used to track the visibility of an element in a window, such as the image below, which shows the visibility of a green square at the top of a scrolling page.

Prior to Intersection Observer, traditional location calculations relied on polling DOM state calculations, which were performed intensively in the main thread and caused page performance problems

Frequent calls to getBoundingClientRect() can also cause browser style recalculation and layout. If it is in an IFrame, we cannot access the element directly because of the same origin policy, and it is difficult to handle the element in an IFrame in the traditional way.

Intersection Observer the Intersection Observer is designed to easily handle elements’ visibility. Intersection Observer We use Intersection Observer to easily monitor elements entering and leaving visual Windows, and to preload and lazily load nodes. Intersection Observer is not a real-time computation based on pixel changes. Its feedback is delayed. This asynchronous approach reduces costly computation and continuous polling of DOM and style queries, and reduces CPU and GPU consumption compared to traditional methods.

The Intersection Observer API registers a callback function that is triggered whenever a monitored element enters or exits another element (or a viewPort), or when the size of the Intersection of two elements changes. This way, the main thread of our site no longer has to work hard to listen for element intersection, and the browser will optimize element intersection management itself.

Note that the Intersection Observer API cannot provide the number of pixels to overlap or which ones to overlap. It is more commonly used to trigger a callback to perform some logic when two elements intersect at about N%.

The Intersection Observer API allows you to configure a callback function that is called when the following occurs

Executes whenever the target element intersects the device window or other specified element. The device window or any other element is called the root element or root. The first time the Observer listens for a target element, you usually need to watch for changes in the intersection of the document’s closest scrollable ancestor, which defaults to the device window if the element is not a descendant of the scrollable element. If you want to observe the intersection with respect to the root element, specify the root element as NULL.

Whether you use the viewport or some other element as root, the API works the same way, executing the callback you provide whenever the visibility of the target element changes so that it crosses the desired crossover point.

The degree of intersection between a target element and a root element is the intersection ratio. This is a representation of the intersection percentage of the target element with respect to the root, which is between 0.0 and 1.0.

Related parameters

  1. IntersectionObserver Option

Create an IntersectionObserver object and pass in parameters and a callback function. The callback function will be executed when the intersection size of target element and root element exceeds the threshold.

let options = {
  root: document.querySelector("#scrollArea"),
  rootMargin: "0px".threshold: 1.0,}let observer = new IntersectionObserver(callback, options)
Copy the code

A threshold of 1.0 means that the callback will be executed when the target element is fully visible in the element specified by the root option.

Optional parameters:

  • root: Specifies the root (root) element to check the visibility of the target. Must be the parent of the target element. If not specified ornull, the default is browser window.
  • rootMargin: root (root) element margin. This is similar to the CSS margin property, such as “10px 20px 30px 40px” (top, right, bottom, left). If root is specified, rootMargin can also be set as a percentage. The value of this attribute is used to calculate the range of the intersection between the root element and target. You can use this attribute to control the contraction or expansion of each side of the root element. The default value is 0.
  • threshold: Can be a single number or an array of numbers. If the intersection of target element and root element reaches this value, the callback function registered by IntersectionObserver will be executed. If you only want to detect when the visibility of the target element exceeds 50% in the root element, you can specify this attribute value of 0.5. If you want the target element to perform a callback for every 25% increase in the visibility of the root element, you can specify an array [0, 0.25, 0.5, 0.75, 1]. The default value is 0(meaning that whenever a target pixel appears in the root element, the callback will be executed). A value of 1.0 means that the callback will not be executed until target is fully present in the root element.

  1. IntersectionObserver Entry

IntersectionObserverEntry object provides the target element and intersecting elements for detailed information. It has the following attributes.

interface IntersectionObserverEntry {
  readonly attribute DOMHighResTimeStamp time;
  readonly attribute DOMRectReadOnly? rootBounds;
  readonly attribute DOMRectReadOnly boundingClientRect;
  readonly attribute DOMRectReadOnly intersectionRect;
  readonly attribute boolean isIntersecting;
  readonly attribute double intersectionRatio;
  readonly attribute Element target;
};
Copy the code

  • Time: indicates the time when the intersection occurs, in milliseconds.
  • RootBounds: Information about the rectangle area of the root element, or null if the root element is not set, as shown in blue.
  • BoundingClientRect: Information about the rectangular region of the target element, the region in the figure with the black border.
  • IntersectionRect: intersecting area of target element and viewport (or root element), intersecting area of blue square and pink square in the figure.
  • IsIntersecting: whether the target element intersects the root element
  • IntersectionRatio: intersecting ratio of target element and viewport (or root element).
  • Target: The target element, the part of the diagram with the black border.
// Define the intersection monitor
var observer = new IntersectionObserver((changes) = > {
  for (const change of changes) {
    console.log(change.time) // The time of the change
    console.log(change.rootBounds) // Information about the rectangular region of the root element
    console.log(change.boundingClientRect) // Information about the rectangular area of the target element
    console.log(change.isIntersection) // Whether the target element intersects the viewport (or root element)
    console.log(change.intersectionRect) // Information about the area where the target element intersects with the viewport (or root element)
    console.log(change.intersectionRatio) // The ratio of the target element to the viewport (or root element)
    console.log(change.target) // The object being observed}}, {})// Start observing a target element
observer.observe(target)

// Stop observing a target element
observer.unobserve(target)

// Close the monitor
observer.disconnect()

// Obtain all IntersectionObserver observed targets
observer.takeRecords()
Copy the code

Note that the callback you register will be executed in the main thread. So the function should be executed as fast as possible. If there are time consuming operation need to be performed, it is recommended to use Windows. RequestIdleCallback () method.

All areas are treated as a rectangle by the Intersection Observer API. If the element is irregular, the shape will be treated as the smallest rectangle containing all of the region of the element. Similarly, if the element’s intersection part is not a rectangle, it will be treated as the smallest rectangle containing all of its intersection region.

This helps to understand the properties of IntersectionObserverEntry IntersectionObserverEntry used to describe the target and the root of intersection.

The intersection root and root margin

Before we start tracking target elements and container elements, we need to know what a container (root) element is. Container elements are also called intersection root, or root element. This can be either the ancestor of the target element or null, using the browser viewport as the container (root).

The rectangle used to describe the boundary of the intersectionRoot element can be resized using the rootMargin property, which is used when creating IntersectionObserver objects. The rootMargin attribute is added as the margin offset to the corresponding margin of the intersection root element, which eventually forms the rectangular boundary of the root element.

Thresholds

The IntersectionObserver API does not perform a callback every time the intersection of elements changes. Instead, it uses the Thresholds parameter. When you create an observer, you can provide one or more values of type number to indicate the percentage of the target element that is visible from the root element. Then, the API’s callback function will execute only if the element reaches a thresholds specified by Thresholds.

For example, you want to be notified every time target’s visibility in the root element exceeds 25% or decreases by 25%. When creating an observer you can specify thresholds to [0, 0.25, 0.5, 0.75, 1]. You can detect when there is a change in each intersection will transmit the parameters of the callback function “IntersectionObserverEntry. IsIntersecting” attribute value to judge the target elements change visibility on the root element. If isIntersecting is true, the target element has reached at least one of the thresholds specified in the thresholds attribute. If it is false, the target element is not visible within the given thresholds.

To get a feel for how Thresholds work, try scrolling the following example. Each colored box has four corners that display their visibility percentage in the root element, so if you scroll root you will see the corners change over time. Each box has a different Thresholds:

  • The first box thresholds attribute value [0.00, 0.01, 0.02,… 0.99, 1.00].
  • The second box has a unique value [0.5].
  • Third box Thresholds press 10% to increment from 0 (0%, 10%, 20%, etc.).
  • Last box [0, 0.25, 0.5, 0.75, 1.0]

Realize the principle of

Asynchronous mechanisms

Intersection Observer. When Chrome or V8 did not find the documentation or blog description of Intersection Observer, UP found the W3C specification. Why polling can effectively reduce overhead compared to JS.

The specification document contains more detailed IDL and development process definitions (including how to create Intersection Objects, put them into queues, and Notify Observer procedures, etc.). 3.2.8. Run the Update Intersection Observations Steps and 3.4 External Spec Integrations

First, how the Processing Model handles all Intersection Observers in each loop is divided into the following steps:

  1. If it is a newly initialized observer, give some initial values:
    • thresholdIndex: 0
    • isIntersecting: false
    • targetRect: DOMRectReadOnlyObject, and x,y,width, and height are 0
    • intersectionRect: DOMRectReadOnlyObject, and x,y,width, and height are 0
  2. If it is an observer of triggering conditions, intersectionRect is calculated using Rect Ratio algorithm described below
  3. TargetArea and intersectionArea were assigned to the range of targetRect and intersectionRect, respectively. The value of Entry attribute can be obtained according to the relationship between targetArea and intersectionArea:
    • intersectionRatio
    • isIntersecting
  4. ThresholdIndex is the first entry index to trigger an observer. Thresholds is better than intersectionRatio, and there is also onepreviousThresholdIndexAs well aspreviousIsIntersectingRecord the status of previous entries ifpreviousThresholdIndex! ThresholdIndex == thresholdIndexobserver, time, rootBounds, targetRect, intersectionRect, isIntersecting, targetAll properties.

This is the body loop that handles all the observers. When does this loop run in the browser engine?

An Intersection Observer processing step should take place during the “Update the rendering” steps, after step 12, run the animation frame callbacks, in the in the HTML Processing Model.

This step is:

13.For each fully active document in docs, Run the update intersection observations steps for that document, passing in now as the timestamp.

It is called Update the rendering stage before V8 Event-loop and after the animation frame callback function is executed, which is called Update the rendering and rendering Update of each container in window. UP is better for calculating intersecting rectangles in this stage. At the same time, in the asynchronous phase, the execution frequency is not high (that is why some intermediate threshold cannot be triggered if scrolling fast), so as to realize the monitoring of the event of the target element without blocking the main thread. Intersection Observer is already triggered very frequently (60fps for most devices, or once every 16.66 miliseconds), Although this frequency is not as good as the main thread polling, it is invisible to the user most of the time, which is suitable for most scenarios. However, if this frequency is not enough for some high-velocity application scenarios, then we can consider the following ideas:

  1. Modify the Intersection Observer callback using setTimeout
  2. Handle wheel events using throttles and scrollTop in CSS
  3. Implement custom intersection detection

I’m not going to expand it here

The Rect thewire calculation

First, understand how rectangle operations are calculated:

  1. The target element’s bounding rectangle (that is, the smallest rectangle that fully encloses the bounding boxes of every component that makes up the element) is obtained by calling getBoundingClientRect() on the target. This is the largest the intersection rectangle may be. The remaining steps will remove any portions that don’t intersect.
  2. Starting at the target’s immediate parent block and moving outward, each containing block’s clipping (if any) is applied to the intersection rectangle. A block’s clipping is determined based on the intersection of the two blocks and the clipping mode (if any) specified by the overflow property. Setting overflow to anything but visible causes clipping to occur.
  3. If one of the containing elements is the root of a nested browsing context (such as the document contained in an <iframe>, the intersection rectangle is clipped to the containing context’s viewport, and recursion upward through the containers continues with the container’s containing block. So if the top level of an <iframe> is reached, the intersection rectangle is clipped to the frame’s viewport, then the frame’s parent element is the next block recursed through toward the intersection root.
  4. When recursion upward reaches the intersection root, the resulting rectangle is mapped to the intersection root’s coordinate space.
  5. The resulting rectangle is then updated by intersecting it with the root intersection rectangle.
  6. This rectangle is, finally, mapped to the coordinate space of the target’s document.

GetBoundingClientRect (); overflow getBoundingClientRect(); overflow getBoundingClientRect(); overflow getBoundingClientRect For example, when

Intersection Observer v2

A Google employee posted a blog post about the proposed Intersection Observer V2, because currently V1 only tells you that a target element scrolls into a window view, but not whether it is overwritten by other elements on the page. Or whether the element has CSS properties such as transform, opacity, filter, etc., which would make the element invisible. It is conceivable that this problem is caused by AD tracking.

For the elements in the root Document (the Document), can pass DocumentOrShadowRoot. ElementFromPoint () to determine the above information, but if the third party in the iframe, is unable to get the information.

Intersection Observer V2 introduces the concept of tracking the actual “visibility” of target elements, as defined by humans. By setting an option in the IntersectionObserver constructor, the intersection of IntersectionObserverEntry instance will contain a isVisible called new Boolean field. A true for the value isVisible implements a strong guarantee from the bottom that the target element is made up of other content completely unobstructed and non-visual applications that will change or distort the display on the screen. In contrast, a value of false means that the implementation cannot be guaranteed.

In one important detail the specification is implemented to allow false negatives to be reported (i.e. setting isVisible to False even if the target element is fully visible and unmodified). Browsers are limited to bounding boxes and straight geometry for performance or other reasons. They don’t try to modify it to achieve pixel-perfect border-radius.

That is, false positives are not allowed under any circumstances (that is, set to a time when the target element is not fully visible and not modified). isVisible true

** Warning ** : Visibility is much more expensive than intersection. Therefore, Intersection Observer V2 cannot be used as widely as Intersection Observer V1. Intersection Observer V2 is focused on fighting fraud and should only be used when visibility information is required and Intersection Observer V1 is not functional.

What does the new code look like in practice?

The IntersectionObserver constructor now requires only two additional configuration properties: delay and trackVisibility. The delay is a number indicating the minimum delay in milliseconds between notifications from an observer for a given target. TrackVisibility is a Boolean value indicating whether the observer will track the visibility of the object.

It is important to note here that when trackVisibilityis true, the delay must be at least 100 (i.e., no more than one notification every 100 milliseconds). As mentioned earlier, visibility is computatively expensive, and this requirement is a precaution against performance degradation and battery drain. A responsible developer will use the maximum allowable delay value.

According to the current specification, visibility is calculated as follows:

  • If the observer’s trackVisibility property is false, the object is considered visible. This corresponds to the current behavior of v1.

  • If the target has a valid transformation matrix other than 2D panning or proportional 2D scaling, the target is considered invisible.

  • If the target or any element in the blockchain it contains has an effective opacity of 1.0, the target is considered invisible.

  • If any filter is applied to the target or any element in the block chain it contains, the target is considered invisible.

  • If the implementation does not guarantee that the target is not completely obscured by other page content, the target is considered invisible.

This means that the current implementation is very conservative without sacrificing visibility. For example, applying a barely noticeable grayscale filter filter: Grayscale (0.01%) or setting opacity 0.99, which is barely visible, would make elements invisible.

Here is a short code example that illustrates the new API capabilities. You can see its click-tracking logic in action in the second part of the demo (but for now, try “watching” the puppy video). Be sure to reactivate Trick Mode to instantly transform yourself into a shady publisher, and see how Intersection Observer V2 prevents tracking illegal AD clicks. The Intersection Observer V2 supported us this time! 🎉

React.lazy

Use React. Lazy in conjunction with useCallback, useReducer, and Intersection Observer. See blog for details

compatibility

IntersectionObserver is currently supported by mainstream browsers except IE and OperaMini. We can use it with progressive support. For the current browser ecosystem, we also need to do a downgrading measure. We can also use IntersectionObserver Polyfill to increase the compatibility of the browser. For details, see Polyfill. IO.

Compatibility Details

Write in the last

Share my possession of TS tutorials, from zero to high order all series, click a link, 0 RMB for www.yidengxuetang.com/pub-page/in…

Refer to the link

  • MDN Intersection Observer
  • W3C Event-Loop
  • html sepc event-loop-processing-model
  • Intersection Observer fails sometimes when i scroll fast
  • Understand Intersection Observer in depth
  • React implement infinity scrolling and lazy load image