Just incase someone is looking for a slightly more flexible answer to finding if an element is hidden by a parent with overflow, this will look at all of the parents of element and check if it is hidden or partially hidden for all of them. It returns a decimal where 1 is completely visible and 0 is completely hidden, and anywhere inbetween. I found it was useful to test if a dropdown list was partially hidden and should be popped up instead of down.
It uses JQuery, for the most part, but underscore was also helpful. This is not optimised at all, so...
function recursivePartialIsVisible(element: HTMLElement): number {
const elementBoundary = {
top: $(element).offset().top,
left: $(element).offset().left,
bottom: $(element).offset().top + $(element).height(),
right: $(element).offset().left + $(element).width(),
height: $(element).height(),
width: $(element).width()
};
const visibility = _.chain($(element).parents())
.map(parent => $(parent))
.filter(parent =>
parent.css('overflow') === 'hidden' ||
parent.css('overflow') === 'scroll' ||
parent.css('overflow') === 'auto' ||
parent.css('overflow-y') === 'hidden' ||
parent.css('overflow-y') === 'scroll' ||
parent.css('overflow-y') === 'auto'
)
.map(parent => {
const parentBoundary = {
top: parent.offset().top,
left: parent.offset().left,
bottom: parent.offset().top + parent.innerHeight(),
right: parent.offset().left + parent.innerWidth(),
height: parent.innerHeight(),
width: parent.innerWidth()
};
if(
elementBoundary.bottom < parentBoundary.top ||
elementBoundary.top > parentBoundary.bottom ||
elementBoundary.left > parentBoundary.right ||
elementBoundary.right < parentBoundary.left) {
return 0;
}
const areaOverlap =
(Math.max(elementBoundary.left, parentBoundary.left) - Math.min(elementBoundary.right, parentBoundary.right))
*
(Math.max(elementBoundary.top, parentBoundary.top) - Math.min(elementBoundary.bottom, parentBoundary.bottom));
const percentageOverlap = areaOverlap / (elementBoundary.height * elementBoundary.width);
return percentageOverlap;
})
.reduce((previous, current) => previous * current, 1)
.value();
return visibility;
}
Note: the maths were borrowed from here