In order to determine the visibility of an element and ensure it is not obscured by other elements, we implemented a solution using several methods. Here are the approaches we employed:
- Utilized window.getComputedStyle to inspect for
visibility:hidden
and display:none
- Employed document.elementFromPoint from various positions, including all corners, to handle common scenarios and enhance accuracy. Corner coordinates were easily obtained via Element.getBoundingClientRect()
Link to Demonstration
HTML
<div id="covering-element"></div>
<div>
<div id="hidden-element"></div>
</div>
<button style="margin-top:100px">Check visibility</button>
CSS
#covering-element {
position: absolute;
width: 100px;
height: 100px;
background: darksalmon;
text-align: center;
}
#hidden-element {
width: 25px;
height: 25px;
background: deeppink;
}
JavaScript
document.querySelector('button').addEventListener('click', function() {
const element = document.getElementById('hidden-element')
alert('Visible = '+isVisible(element))
})
function isVisible(element) {
if(!isVisibleByStyles(element)) return false
if(isBehindOtherElement(element)) return false
return true
}
function isVisibleByStyles(element) {
const styles = window.getComputedStyle(element)
return styles.visibility !== 'hidden' && styles.display !== 'none'
}
function isBehindOtherElement(element) {
const boundingRect = element.getBoundingClientRect()
// adjust coordinates to get more accurate results
const left = boundingRect.left + 1
const right = boundingRect.right - 1
const top = boundingRect.top + 1
const bottom = boundingRect.bottom - 1
if(!element.contains(document.elementFromPoint(left, top))) return true
if(!element.contains(document.elementFromPoint(right, top))) return true
if(!element.contains(document.elementFromPoint(left, bottom))) return true
if(!element.contains(document.elementFromPoint(right, bottom))) return true
return false
}
Note: Node.contains returns true if the given element is the node itself or a descendant of it. To solely check for the exact element without including its descendants, utilize
document.elementFromPoint(...) !== element
in the conditional statements within
isBehindOtherElement