How to Know when an Element Gets Visible in the Screen During Scrolling

Many times, during scrolling, it required to know when an element gets visible in the screen so that the future course of action can be decided. Some examples can be lazy loading of images, infinite scrolling etc.

Previously finding whether an element has entered the screen or viewport used to be a pain, but newer APIs have made this job quite easier with better performance. The old method is also described briefly here, but you should definitely start using the new method now.

Note : screen and viewport are used interchangeably in this tutorial.

The Old Way : Listening to the scroll Event

The old way is to attach a scroll event handler to the window object, and use getBoundingClientRect() to calculate the position of the element relative to the viewport. The getBoundingClientRect method returns a few properties, which could be used to know whether the element is hidden or visible in the current viewport :

  • top : distance from the top of the viewport
  • bottom : distance from the bottom of the viewport

Positive values of top and bottom mean they lie on the same side. Negative values mean they lie on either sides.

For example a value of 100px for top means the top of the element is at distance 100px below the top of the screen (so top of element is visible in screen). While if the value of top is -200px, it means the top of the element above 200px from the top of the screen (so top of element is not visible in screen).

To know whether the element is fully visible in viewport, you will need to check whether top >= 0, and bottom is less than the screen height.

In a similar way you can also check for partial visibility, top is less than screen height and bottom >= 0.

The Javascript code could be written as :

window.addEventListener('scroll', function() {
	var element = document.querySelector('#main-container');
	var position = element.getBoundingClientRect();

	// checking whether fully visible
	if(position.top >= 0 && position.bottom <= window.innerHeight) {
		console.log('Element is fully visible in screen');
	}

	// checking for partial visibility
	if(position.top < window.innerHeight && position.bottom >= 0) {
		console.log('Element is partially visible in screen');
	}
});

scroll events have a lot of performance issues. Performance effect is so bad that browsers have brought forward a new API to solve this problem.

The New Way : Using Intersection Observer API

The Intersection Observer API makes it possible to know when an element enters or exits the browser viewport. There is no need to attach any event handlers. Furthermore, this API is asynchronous — monitoring element for visibility is not done on the main thread. This is a major performance boost.

The Intersection Observer API can calculate intersection between a target element and the browser viewport. In simple terms it can tell whether the target element and the screen overlap (through isIntersecting property), and by how much percentage they overlap (through a intersectionRatio property).

You can create a new IntersectionObserver object, and set a threshold. threshold is a number between 0 and 1, that represents the viewable area of the target element in the screen. For example, 0 represents no area of element is visible. A value of 0.10 represents about 10% area is viewable in screen. Value of 1 means element is fully viewable in screen.
You can even specify multiple thresholds.

Intersection Observer will fire a callback function, once the threshold is passed in either direction. For example if you have set threshold to 0.10, callback function will be invoked everytime when viewable area becomes greater than 10% or becomes less than 10%.

In the current case where we just want to know when element becomes viewable in screen, the Javascript code will be :

var observer = new IntersectionObserver(function(entries) {
	// isIntersecting is true when element and viewport are overlapping
	// isIntersecting is false when element and viewport don't overlap
	if(entries[0].isIntersecting === true)
		console.log('Element has just become visible in screen');
}, { threshold: [0] });

observer.observe(document.querySelector("#main-container"));

If we want to know when element becomes fully visible in screen :

var observer = new IntersectionObserver(function(entries) {
	if(entries[0].isIntersecting === true)
		console.log('Element is fully visible in screen');
}, { threshold: [1] });

observer.observe(document.querySelector("#main-container"));

The Intersection Observer API has more features, but further details are not discussed here. You can checkout out Intersection Observer API on MDN for more.