How to detect if an element inside a scrollable block is visible to user (i.e. is in the visible area of the scrollable parent)?
Is there a universal solution, not involving iterating over all parent nodes that have scroll?
P.S. One idea I had was getElementAtPoint
, however it gives me headaches when I need to determine if at least 50% of the element is visible. So ideally the solution must involve collision detection between two rectangles: the element rectangle and the window.
P.P.S. Another idea I've come up with is to use scrollIntoView
on the element in question, determine the difference in its position, and then scroll it back to original position. It appears scrollIntoView
always does the right thing – scrolls both window and the inner scrollable blocks!
I'm afraid this can't be done without iterating, and even less cross-browser, with some simple code.
Here's an example, how this can be done in IE. Unfortenately other browsers seem to return different values from body/html.getBoundingClientRect()
. Also margins are treated differently, (IE ignores, others take them account).
getVisibilityPercent = function () {
var target = document.getElementById('target'),
height = target.offsetHeight,
parent = target.parentElement,
targetRect = target.getBoundingClientRect(),
tLim, bLim,
percent = 1;
while (parent) {
parentRect = parent.getBoundingClientRect();
tLim = Math.max(targetRect.top, parentRect.top);
bLim = Math.min(targetRect.bottom, parentRect.bottom);
percent *= (bLim - tLim) / height;
percent = (percent < 0) ? 0 : percent;
parent = parent.parentElement;
}
return +((percent * 100).toFixed(2));
};