For more tips like this, sign up to the weekly newsletter!

Use boundingClientRect to get an element's position

To get an HTML element's position, use boundingClientRect(). This function returns the top, left, bottom, and right values, along with a few others. These positions are relative to the viewport.

const boundingClientRect = document.querySelector(...).getBoundingClientRect();

boundingClientRect.left;
boundingClientRect.right;
boundingClientRect.top;
boundingClientRect.bottom;

The viewport

The viewport takes the scroll positions and any iframes into account. As a result, if the window or any elements in it are scrolled, the positions returned from the function changes.

This means that getBoundingClientRect() returns the position the user sees the element. Due to this fact, the top/left can easily go negative.

To the document

To get the coordinates relative to the document instead of the viewport, add the scroll positions of all the ancestors:

const calculateScroll = (e) => {
    if (e) {
        const [scrollTop, scrollLeft] = calculateScroll(e.parentNode);
        return [(e.scrollTop || 0) + scrollTop, (e.scrollLeft || 0) + scrollLeft];
    }else {
        return [0, 0];
    }
};

And finally, add the scrollTop/scrollLeft to the coordinates:

boundingClientRect.top + scrollTop
boundingClientRect.bottom + scrollTop
boundingClientRect.left + scrollLeft
boundingClientRect.right + scrollLeft

These coordinates are now relative to the document, so scrolling any of the element's parents won't change them.

Try it
References
Learn more: