The Intersection Observer API has since December 2023 in Chrome and Edge 120 been shipped with the new options
property scrollMargin
. However, its convenience seems to be understated. Even the MDN documentation on the Intersection Observer constructor has yet to be updated with information about this property. It is definitely an upgrade to the Intersection Observer API, so I want to tell you more about it, particularly because it has already helped with with projects at work.
rootMargin
The Problem with Intersection Observer’s The Intersection Observer API is a JavaScript API that makes it possible to know whether a DOM element is in the viewport or not. An intersection observers constructor takes an options object, in which a rootMargin
can be specified. Its value is “a string which specifies a set of offsets to add to the root’s bounding box when calculating intersections, effectively shrinking or growing the root […] The syntax is approximately the same as that for the CSS margin property” (MDN).
To give you an example: if you want some code to run before the element is actually in view, rootMargin: "25%"
will make the Intersection Observer report an intersection when the observed element is 25% away from the viewport.
However, a problem arises if the Intersection Observer:
- uses the default root (the document’s viewport)
- is specified with a
rootMargin
- observes an element inside a scroll container
In that case, the intersection in the scroll direction is reported as if no rootMargin
has been specified. This makes it impossible to get an intersection before the element in a scroll container is actually visible, which is a problem when trying to lazy load thing just before they are visible.
The workaround is to use the scroll container as the root instead of Intersection Observer’s default root. But it would be convenient if it was possible to keep using the default root!
scrollMargin
is the New Solution
The new Intersection Observer options property scrollMargin
aims to rectify this. Without it, when the root is the document viewport, the scroll containers are clipped away. This is the cause of the aforementioned problem. With the new Intersection Observer property, each scroll container is expanded by the scrollMargin
when calculating the intersection.
A Typical Use Case
The use case for the scrollMargin
property is using it as an indicator to request data when it is about to be scrolled into view. That’s called lazy loading, the point of which is to not load data that is so far off screen it’s possible the user never scrolls to see it.
The following Pen lazy loads data both in the vertical and horizontal directions. The UI/UX is like a streaming service, which is exactly where my use case and thus learning of this feature comes from. Similar use cases are scrolling carousels for eCommerce, news, images, etc.
Video Examples
This is what lazy loading looks like without scrollMargin
in place. Notice how you can see the element before the data is ready, and there is a noticable loading delay.
Here’s a video example of when we have scrollMargin
in place in a supporting browser. Notice that the data is loaded ahead of time and it’s ready to go when the user gets there.
In the video above it looks like we’re just horizontally scrolling some elements that are already loaded, but rest assured, they are being loaded just in time and are still properly lazy loading.
Browser Support
At the time of writing (January 2025), only Chrome and Edge since version 120 support this new property. The status of the feature can be followed on the Chrome Platform Status Feature: Intersection Observer Scroll Margin page. It is already a part of the W3C’s Intersection Observer specification. When it comes to Safari, it has been reported as a missing feature on the Webkit Bugzilla platform since Nov 2023.
Unfortunately, I will caution against using scrollMargin
as a progressive enhancement. The consequence is that in Safari, the data will not load before it is scrolled into view, and the user will see the data appearing. This sounds innocent enough, but there is a problem with VoiceOver in Safari. It’s a “vicious circle” type of problem: in order for the screen reader to navigate to the element, it needed to have its data loaded, but in order to load its data, it needed to be scrolled into view.
In spite of the lacking Safari support, I wanted to write about this property. The reason is that I think we as web developers should all push for web browser interoperability, and from my experience, I think the web platform would benefit from having scrollMargin
supported.
Thanks to Johannes Odland.
Cool feature. Pity that also Firefox doesn’t support it yet.
https://caniuse.com/mdn-api_intersectionobserver_scrollmargin