I have spent a lot of time with you and i realized one thing. I always being grateful. Either you are the thing that I should be grateful for or anything. All the little things you did for me are…
The Intersection Observer is a Web API that facilitates visibility tracking of elements within the viewport or its parent element(s). Some practical use cases could be lazy loading for images, dynamic imports based on interaction, scroll-spying navigation bars, among others. This API encapsulates a lot of logic that before its time, a developer would’ve had to build from scratch with several performance considerations in mind — believe me, mastering how to use the Intersection Observer is 100% worth it.
Before we start I want to acknowledge how was life before this API existed. We know that strategies like lazy loading or scroll-spying have existed for a while, and in order to achieve this, developers had to take into account several techniques and best practices to make it work smoothly and in a performant way. Some of the main complexities orbited around:
After jumping through some hoops, developers were able to achieve what the Intersection Observer seamlessly does. Now, don’t get me wrong, if you nail all of the above (and a couple more) you could create something as performant (or more) as the Intersection Observer. So if you’re up for the challenge, do it (let me know if this is something you’d be interested to read about in the comments).
But let’s not forget that this is adding a good amount of code to your codebase, it’s more code to be maintained and–hopefully–to be tested.
The Intersection Observer hides many implementation details and includes the different considerations we just talked about. Everything is boiled down into a class: IntersectionObserver
.
By instantiating an IntersectionObserver
you get an instance of an observer that knows how to detect intersections between a target element and its direct or indirect parent, being the browser viewport the highest level one (and default). All of this based on a configuration. This is when things start to get tricky… the configuration.
The scope of this tool is to showcase how a threshold: 0
or threshold: 1
interacts with negative root margins (using either pixels or percentages). These terms might sound confusing so let’s dive in.
An instance of the IntersectionObserver
that will be detecting intersections.
The element being observed by the said observer. The same observer can observe several targets.
🌳 Root configuration (root
parameter)
The ancestor used to detect the intersection. In order to an intersection to happen the target needs to be a descendant of the root. By default the root is the viewport, as seen in the following image:
Picture this as sort of checkpoints along the area of the target. This checkpoints go from 0
to 1
. Float values are valid. So as an example:
I want to highlight the “when the intersection of the target happens” part of both items above. The IntersectionObserver only triggers when there are intersections happening.
See the following image as a reference:
Remember the CSS Box Model? Well this API applies a similar principle to the root. This provides the ability to customize where the intersections are detected. As an example let’s look at this image adding the following configuration: rootMargin: -100px 0px -250px 0px
and how the intersection positions change:
A similar result can be achieved by using percentages instead of pixels:
The minimum you need to do to use this API is to instantiate it and observe
a target.
The callback is a good old JavaScript function that receives two parameters:
The callback
will be called in two scenarios:
Whenever the callback gets called, an array of entries
will be received and there are a several attributes that can be used. Nevertheless, let’s focus on two:
By understanding the different concepts we’ve just covered, you should be able to achieve a myriad of ideas and interactions. There are infinite combinations that can be done between the threshold
, the rootMargin
, and the implementation of the callback using isIntersecting
and intersectionRatio
.
I encourage you to play around with the tool mentioned above and try to find the different configurations that might work for your specific case. Here I’ll try to list some configurations I’ve used for different cases:
This configuration aims to solve the typical navigation that sets an active
state to the items in it depending on the section being visible as the user scrolls:
This brief implementation will execute the callback every time a section touches the top edge of the viewport as the user scrolls up, therefore the rootMargin top is 0%
and bottom is -100%
. Now it’s on you to come up with a way to map the section to the navigation item to toggle its state.
Lazy loading images require a slightly different approach as requesting an image can take long depending on its weight. So we’d need to do a different configuration:
Notice how the rootMargin is now positive. Even though this tool doesn’t provide a way to make it happen, as we discussed above, this behaves similarly to the box model. Negative margins grow inward, positive margins grow outwards. This means that the images will trigger an intersection 50% outside of the viewport. See the following image as a reference:
The rootMargin 50%
is a number that can be adjusted depending on the weight of the images or specific needs that you may have.
The approach for dynamic imports is similar to the lazy load of the images. Although, if code splitting is done right the files should be small if not tiny so the number could decrease from 50% to a 10%.
Using this configuration will allow you to detect the components that are about to be shown on the screen outside of the viewport. Giving you enough time to dynamically import it and then use it.
Thanks so much for the read. Please feel free to reach out if you have any questions or concerns. Happy to connect.
The Sprint Review is the event where the Scrum Team and the Stakeholders come together to inspect the outcome of the Sprint (aka the Increment that meets the Definition of Done), they collaborate on…
When I started out in web development, I have started like most folks — naming css in the way it made the most sense for me. Because of this I would run into problems like having to think of the name…
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent…