DEV Community

Cover image for Check if an element is visible in the viewport
Phuoc Nguyen
Phuoc Nguyen

Posted on • Originally published at phuoc.ng

Check if an element is visible in the viewport

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:

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)
    );
};
Enter fullscreen mode Exit fullscreen mode

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.

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
    );
};
Enter fullscreen mode Exit fullscreen mode

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.

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:

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);
};
Enter fullscreen mode Exit fullscreen mode

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.

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:

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
    );
}
Enter fullscreen mode Exit fullscreen mode

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:

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
    );
}
Enter fullscreen mode Exit fullscreen mode

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.

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:

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

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

    return () => {
        container.removeEventListener('scroll', handleScroll);
    };
}, []);
Enter fullscreen mode Exit fullscreen mode

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:

Top comments (3)

Collapse
 
sebastianccc profile image
Sebastian Christopher

It’s nice to see a post about this, but might I ask the reason for the sudden change to React? Besides that, awesome post :)

Collapse
 
phuocng profile image
Phuoc Nguyen

Did you mean that why the examples use React instead of pure JavaScript?

Collapse
 
sebastianccc profile image
Sebastian Christopher

Yes. Suddenly it was React ;)