


A Few Functional Uses for Intersection Observer to Know When an Element is in View
Intersection Observer API: Real-time monitoring of whether elements are visible
You may not know that JavaScript has quietly accumulated many observers in recent years, and Intersection Observer is one of the powerful tools. Observers are objects that monitor specific events in real time, just as birders sit in their favorite place and wait for the bird to appear. Different observers observe different goals.
The first observer I came into contact with was Mutation Observer, which detects changes to the DOM tree. It was unique at the time, but now we have more observers.
Intersection Observer observes the "intersection" between an element and its ancestor element or the visible area of the page (i.e., the viewport) (i.e., the element enters or leaves the viewport). It's a bit like watching a train pass by a station. You can see when the train enters the station, when it leaves the station and how long it has stopped.
Understanding when an element is about to enter the field of view, when it disappears, or how long it has passed since it has entered the field of view is very practical. Therefore, we will learn about some use cases - after the code to create the IntersectionObserver object through the Intersection Observer API.
IntersectionObserver Quick Overview
At the time of writing, the Intersection Observer API has received extensive support.
The browser supports data from Caniuse, which contains more details. The number indicates that the browser supports this feature in this version and later.
Desktop
Mobile/Tablet
However, if you want to check if it is supported when using Intersection Observer, you can check if the IntersectionObserver property exists in the window object:
if(!!window.IntersectionObserver){} /* or */ if('IntersectionObserver' in window){}
OK, let’s take a look at the creation of the object:
var observer = new IntersectionObserver(callback, options);
The constructor of the IntersectionObserver object accepts two parameters. The first is the callback function, which will be executed when the observer notices the intersection and passes some data about the intersection asynchronously.
The second (optional) parameter is options , an object containing information that defines what "cross" is. We may not want to know when the element is about to enter the field of view, but only when it is fully visible. Things like this are defined by the options parameter.
Options has three properties:
- root – The ancestor element/viewport with which the observed element will cross. Think of it as the station where the train will cross it.
- rootMargin – The perimeter of the root element, shrinking or enlarging the observation area of the root element to detect crossovers. It is similar to the CSS margin property.
- threshold – an array of values (between 0 and 1.0), each representing the distance the element crosses or crosses the root, at which the callback will be triggered.
Suppose our threshold is 0.5. A callback is triggered when an element enters or exceeds its semi-visible threshold. If the value is [0.3, 0.6]
, a callback will be triggered when the element enters or exceeds its 30% visible threshold and its 60% visible threshold.
That’s all about the theory now. Let's see some demos. First of all, lazy loading.
Use Case 1: Lazy loading images
To view the load tag
, check this page because the embedded demo does not display the tag.
CSS-Tricks has already thoroughly introduced lazy loading, which is usually done like this: display a lightweight placeholder, the image will be displayed at the placeholder's position, and then replace it with the expected image as it enters (or is about to enter) the field of view. Trust me, it's not lazy to implement this at all - that is, until we get some native code to use.
We will apply the same mechanism. First, we have a bunch of images and define a placeholder image that is initially displayed. We use a data attribute to carry the URL of the original image to be displayed, which defines the image to be loaded when the actual image enters the field of view.
<img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/174520555311750.jpg?x-oss-process=image/resize,p_40" class="lazy" alt="A Few Functional Uses for Intersection Observer to Know When an Element is in View"><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/174520555481250.jpg?x-oss-process=image/resize,p_40" class="lazy" alt="A Few Functional Uses for Intersection Observer to Know When an Element is in View"><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/000/174520555431263.jpg?x-oss-process=image/resize,p_40" class="lazy" alt="A Few Functional Uses for Intersection Observer to Know When an Element is in View">
The rest are scripts.
let observer = new IntersectionObserver( (entries, observer) => { entries.forEach(entry => { /* handle each cross here*/ }); }, {rootMargin: "0px 0px -200px 0px"});
The callback function above is an arrow function (although you can use a normal function).
The callback function receives two parameters: a set of entries containing information about each intersection; and the observer itself. These entries can be filtered or looped through, and then process the cross entries we want. As for options, I only provide the rootMargin value, allowing the root and threshold properties to take their default values.
The default value of root is the viewport, and the default value of threshold is 0 - this can be roughly interpreted as "notifying me the moment the element appears in the viewport!"
However, strangely, I used rootMargin to reduce the bottom of the viewport's observation area by 200 pixels. We don't usually do this in lazy loading. Instead, we might increase margins or keep it default. However, in this case, we usually don't reduce margins. I do this just because I want to demonstrate the original image loaded at the threshold of the observation area. Otherwise, all operations will occur out of view.
When the image intersects the viewing area of the viewport (200 pixels above the bottom in the demonstration), we replace the placeholder image with the actual image.
let observer = new IntersectionObserver( (entries, observer) => { entries.forEach(entry => { /* Placeholder replacement*/ entry.target.src = entry.target.dataset.src; observer.unobserve(entry.target); }); }, {rootMargin: "0px 0px -200px 0px"});
entry.target
is the element observed by the observer. In our case, these are image elements. Once the placeholder is replaced in the image element, we no longer need to observe it, so we call the observer's unobserve
method on it.
Now that the observer is ready, it's time to start observing all images using its observe
method:
document.querySelectorAll('img').forEach(img => { observer.observe(img) });
That's it! We've lazy to load the image. Go to the next demo.
Use Case 2: Automatically pause video when elements leave view
Suppose we watch videos on YouTube and (for whatever reason) we want to scroll down to read the comments. I don't know how you are, but I usually don't pause the video before doing this, which means I miss some videos while browsing.
Wouldn't it be nice if the video will automatically pause when we're scrolling away from the video? It would be even better if the video resumes playing when it re-enters the field of view, so there is no need to click the play or pause button.
Intersection Observer can certainly do this.
Here is our video in HTML:
<video controls="" src="OSRO-animation.mp4"></video>
Here is how we pause and play videos during each crossover (i.e. entry):
let video = document.querySelector('video'); let isPaused = false; /* flag for automatically pausing video*/ let observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if(entry.intersectionRatio!=1 && !video.paused){ video.pause(); isPaused = true; } else if(isPaused) {video.play(); isPaused=false} }); }, {threshold: 1}); observer.observe(video);
Before I show you how to pause and play the video during each cross (i.e. entry), I want to draw your attention to the threshold property of options .
The value of threshold is 1. root and rootMargin will take the default values. This is equivalent to saying, “Hey, let me know once the element is fully visible in the viewport.”
Once a cross occurs and a callback is triggered, we will pause or play the video according to the following logic:
I'm not calling unobserve
for the video, so the observer keeps watching the video and pauses every time the video leaves view.
Use Case 3: View how much content has been viewed
This can be explained and implemented in a variety of ways based on your content and your preferred way to measure how much content has been viewed.
For a simple example, we will observe the last paragraph of each post in the list of posts on the page. Once the last paragraph of the article is fully visible, we will assume that the article has been read—just like we might say that seeing the last car of a train is equivalent to seeing the entire train.
This is a demo that shows two articles on the page, each containing multiple paragraphs of text.
Our simplified HTML looks like this:
<div></div> <h2 id="Article">Article 1</h2> <p></p> <h2 id="Article">Article 2</h2> <p></p>
let n=0; /* Total number of articles viewed*/ let count = document.querySelector('#count'); let observer = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if(entry.isIntersecting){ count.textContent= `articles fully viewed - ${ n}`; observer.unobserve(entry.target); } }); }, {threshold: 1}); document.querySelectorAll('article > p:last-child').forEach(p => { observer.observe(p) });
During each crossover (i.e. the last paragraph of the article is fully visible), we increment a counter: n, which represents the total number of articles read. We then display that number above the article list.
Once we have calculated the crossover of the last paragraph, we don't need to observe it anymore, so we call unobserve
on it.
Thank you for your participation!
This is the example in this article we will view together. You may have learned how to use it to observe elements and trigger events based on their intersection with the viewport.
That is, caution is required when making visual changes based on cross data obtained through observers. Of course, Intersection Observer is very convenient when recording cross-data. However, when it is used to make changes on the screen, we need to make sure the changes don't lag, which is a possibility because we basically make changes based on data retrieved asynchronously . This may take some time to load.
As we can see, each cross entry has an attribute set that conveys information about the cross. In this post, I did not cover all of these properties, so be sure to check them out.
The image is preserved in its original format. Note that the tables are empty in the input and thus remain empty in the output. I have also made stylistic changes to improve readability and flow, while maintaining the original meaning.
The above is the detailed content of A Few Functional Uses for Intersection Observer to Know When an Element is in View. For more information, please follow other related articles on the PHP Chinese website!

If you've ever had to display an interactive animation during a live talk or a class, then you may know that it's not always easy to interact with your slides

With Astro, we can generate most of our site during our build, but have a small bit of server-side code that can handle search functionality using something like Fuse.js. In this demo, we’ll use Fuse to search through a set of personal “bookmarks” th

I wanted to implement a notification message in one of my projects, similar to what you’d see in Google Docs while a document is saving. In other words, a

Some months ago I was on Hacker News (as one does) and I ran across a (now deleted) article about not using if statements. If you’re new to this idea (like I

Since the early days of science fiction, we have fantasized about machines that talk to us. Today it is commonplace. Even so, the technology for making

I remember when Gutenberg was released into core, because I was at WordCamp US that day. A number of months have gone by now, so I imagine more and more of us

The idea behind most of web applications is to fetch data from the database and present it to the user in the best possible way. When we deal with data there

Let's do a little step-by-step of a situation where you can't quite do what seems to make sense, but you can still get it done with CSS trickery. In this


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment

mPDF
mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

SublimeText3 Mac version
God-level code editing software (SublimeText3)

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

Dreamweaver CS6
Visual web development tools