Check if an element is visible in the viewport
Tags: webdev, javascript, react, tutorial
Published: 2024-03-26 01:50:42

Knowing how to check if an element is visible in the viewport is incredibly useful in web development. Here are some real-life examples where this knowledge can come in handy:

-   **Infinite scrolling:** Websites that use infinite scrolling need to constantly check if new content is visible in the viewport to load more content.
-   **Analytics:** By tracking how long users spend looking at specific elements on a page, you can gain valuable insights into what's working and what's not.
-   **Animations:** When using animations, you'll want to make sure that elements are only animated when they're visible in the viewport. This helps improve website performance and ensures your animations look smooth and polished.

By understanding how to check if an element is visible in the viewport, you can create more dynamic and engaging websites that provide a better user experience.

Before diving into the IntersectionObserver API, there are a few approaches you can take to determine if an element is visible in the viewport. In this post, we'll explore some of them.

## Checking if an element is visible in the window

If you're wondering how to check if an element is visible in the viewport, one way to do it is by using the element's `getBoundingClientRect()` method. This method gives you the size of the element and its position relative to the viewport. By comparing these values to the viewport's position and dimensions, you can easily determine whether the element is visible or not.

To help you out, here's an example function that uses the `getBoundingClientRect()` method:

```js
const isElementVisible = (ele) => {
    const rect = ele.getBoundingClientRect();
    return (
        rect.top >= 0 &&
        rect.left >= 0 &&
        rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
        rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
};
```

The `isElementVisible` function checks if an element is visible in the viewport. First, it gets the element's size and position relative to the viewport using the `getBoundingClientRect()` method. Then, it checks if all four sides of the element are within the bounds of the viewport.

To be visible, the element's top and left sides must be greater than or equal to zero. Additionally, the element's bottom and right sides must be less than or equal to either `window.innerHeight` or `document.documentElement.clientHeight` for height, and `window.innerWidth` or `document.documentElement.clientWidth` for width.

If all four sides of the element are visible in the viewport, `isElementVisible` returns `true`. Otherwise, it returns `false`.

## Checking if an element is visible within a scrollable container

With a slight modification to the `isElementVisible` function, we can now determine if an element is visible within a scrollable container.

```js
const isElementVisibleInContainer = (ele, container) => {
    const rect = ele.getBoundingClientRect();
    const containerRect = container.getBoundingClientRect();
    return (
        rect.top >= containerRect.top &&
        rect.left >= containerRect.left &&
        rect.bottom <= containerRect.bottom &&
        rect.right <= containerRect.right
    );
};
```

To determine if an element is visible within a scrollable container, the `getBoundingClientRect()` method is used to get the size and position of both the element and the container. Then, it checks if all four sides of the element are within the bounds of the container.

For an element to be considered visible in a scrollable container, its top and left sides must be greater than or equal to the container's top and left sides. In addition, its bottom and right sides must be less than or equal to the container's bottom and right sides.

Give it a try by scrolling up and down the playground below to see how it works.

{% codesandbox gxq7f8 %}

## Checking if an element is partially visible in a scrollable container

We can improve the `isElementVisibleInContainer` function by modifying it to check if an element is partially visible within a container. This modification can be useful when you want to trigger specific actions when an element becomes partially visible.

Here's the updated function:

```js
const isElementPartiallyVisibleInContainer = (ele, container) => {
    const rect = ele.getBoundingClientRect();
    const containerRect = container.getBoundingClientRect();

    const topIsVisible = rect.top >= containerRect.top && rect.top < containerRect.bottom;
    const bottomIsVisible = rect.bottom > containerRect.top && rect.bottom <= containerRect.bottom;
    const leftIsVisible = rect.left >= containerRect.left && rect.left < containerRect.right;
    const rightIsVisible = rect.right > containerRect.left && rect.right <= containerRect.right;

    return (topIsVisible || bottomIsVisible) && (leftIsVisible || rightIsVisible);
};
```

The `isElementPartiallyVisibleInContainer` function is similar to the `isElementVisibleInContainer` function, but with a twist. Instead of checking if all four sides of the element are within the container, it only checks if any side of the element is within the container.

To find out if an element is partially visible in a scrollable container, we compare each side of the element to each side of the scrollable area. If any part of the element overlaps with any part of the scrollable area, we say it's partially visible.

Give it a try by scrolling up and down on the following playground to see how it works.

{% codesandbox x59wwm %}

## Using the scrollY and innerHeight properties

Another way to check if an element is visible in the viewport is by comparing the element's position with the current scroll position and viewport height. This approach is similar to the first method, but it doesn't require calling `getBoundingClientRect()`.

Here's an example function that uses this method:

```js
const isElementVisible = (ele) => {
    const scrollTop = window.scrollY;
    const windowHeight = window.innerHeight;
    const eleTop = ele.offsetTop;
    const eleHeight = ele.offsetHeight;

    return (
        eleTop - scrollTop < windowHeight &&
        eleTop + eleHeight > scrollTop
    );
}
```

First, the `isElementVisible` function retrieves the current scroll position of the window using `window.scrollY`, and the height of the viewport using `window.innerHeight`. It then obtains the top position of the element relative to its offset parent using `el.offsetTop`, as well as its height using `el.offsetHeight`.

The function returns a boolean value, indicating whether any part of the element is visible within the bounds of the viewport. Specifically, it checks if either (1) any part of the top edge of the element is above or at the top edge of the viewport AND any part of its bottom edge is below or at the bottom edge of it OR (2) all parts of its edges are inside or partially inside both edges of the viewport. If either condition is met, then the function returns `true`; otherwise, it returns `false`.

You can also modify the `isElementVisible` function to check if an element is partially visible within a scrollable container. This modification can be useful when you want to trigger specific actions when an element becomes partially visible.

Here is an updated version of the function:

```js
const isElementPartiallyVisibleInContainer = (ele, container) => {
    const scrollTop = container.scrollTop;
    const containerHeight = container.offsetHeight;
    const eleTop = ele.offsetTop - container.offsetTop;
    const eleHeight = ele.offsetHeight;

    return (
        eleTop + eleHeight > scrollTop &&
        eleTop < scrollTop + containerHeight
    );
}
```

First, we get the current position of the scrollable container using `scrollTop`. Then, we calculate how much space is available in that container using `offsetHeight`. Next, we get the position of our target element relative to its parent using `offsetTop` and subtract that from `container.offsetTop` to get our target's position relative to its parent. Finally, we check if any part of our target is visible in its parent by comparing its top and bottom positions with those of its parent.

Try it out for yourself by scrolling up and down in the playground below.

{% codesandbox ynrhyz %}

## Checking element visibility while users scroll

In web development, it's common to need to check if an element is visible to the user as they scroll down a page. One straightforward way to do this is to handle the `scroll` event. This involves listening for the `scroll` event on either the window object or the container element, and then checking if the element is currently visible within the viewport or its scrollable container.

To give you an idea of how this works, here's an example function that implements this approach:

```tsx
const handleScroll = () => {
    const isVisble = isElementPartiallyVisibleInContainer(ele, container);
};

React.useEffect(() => {
    container.addEventListener('scroll', handleScroll);

    return () => {
        container.removeEventListener('scroll', handleScroll);
    };
}, []);
```

## The drawbacks of using the scroll event to check element visibility

Although using the `scroll` event to determine element visibility is a viable approach, it has some limitations that you should be aware of.

Firstly, this method can be resource-intensive and can negatively impact page performance, especially if you're checking many elements or if the container being scrolled is large. This is due to the scroll event firing many times per second during scrolling, and each time it fires, you are performing calculations on all elements that need to be checked for visibility.

Secondly, when using this method, there may be instances where an element appears visible in the viewport but is not actually within view due to overlapping elements or other layout issues. For example, an element may be partially obscured by another element or only visible for a brief moment during scrolling.

Lastly, if you have multiple containers that can be scrolled independently (e.g., nested scrollable areas), this method might not work correctly since the calculation of `elementTop` and `containerTop` will depend on which container is currently being scrolled.

Overall, while using the `scroll` event to check element visibility can be useful in certain situations, it's important to keep its limitations in mind and use it judiciously to avoid impacting page performance.

## Conclusion

To determine if an element is visible on a webpage, there are a few different methods you can use. The most straightforward approach is to use the `getBoundingClientRect()` method to check if all four sides of the element are within the viewport or container. Another way is to compare the element's position with the current scroll position and viewport height using `scrollY` and `innerHeight`. You can even modify these functions to check if an element is fully or partially visible within a scrollable container.

While using the `scroll` event to check element visibility can be helpful in some cases, it's important to be mindful of its limitations and use it wisely to avoid negatively impacting page performance. In this series, we'll explore how to achieve similar functionality with the IntersectionObserver API.

---

If you want more helpful content like this, feel free to follow me:

-   [DEV](https://dev.to/phuocng)
-   [GitHub](https://github.com/phuocng)
-   [Website](https://phuoc.ng)