Skip to content

Instantly share code, notes, and snippets.

@rdillmanCN
Created December 30, 2017 09:26
Show Gist options
  • Save rdillmanCN/b897ffdb77db9c8640cc3b317f601755 to your computer and use it in GitHub Desktop.
Save rdillmanCN/b897ffdb77db9c8640cc3b317f601755 to your computer and use it in GitHub Desktop.
If the element were in the view-port, could we see it?
/**
* Is the element hidden from view? Here are the various ways this cold be.
* * Via css with opacity, display, or visibility.
* * Removed from the DOM, or not yet appended to the DOM
* * Within the overflow of a ancestor.
* * One of the methods above but applied to an ancestor element.
*
* @param {HTMLNode} el - element to examine
* @return {Boolean} Could the element be visible
*/
function isHidden(el) {
var parent = el.parentNode;
// if the element doesn't exist in the DOM
if (!isAttached(el) || !isAttached(el.parentNode)) {
return true;
}
// body is always visible so stop here
if (isBody(el)) {
return false;
}
// If any are true then we are hidden we can stop here
if (checkHiddenStyle(el)) {
return true;
}
// We are visible so check if our parent is body and if so stop here
if (isBody(parent)) {
return false;
}
// Is our parent hidden if so stop here
if (checkHiddenStyle(parent)) {
return true;
}
// check overflow then check offset if we are hidden in the offset stop here
if (checkOverflow(parent) && isOffsetHidden(el)) {
return true;
}
// Second verse same as the first
return isHidden(parent, el.getBoundingClientRect());
}
/**
* Get the value of a calculated style
*
* @param {HTMLNode} el - The element to examine
* @param {string} property - The style property to check
* @return {string} - the matching property
*/
function getStyle(el, property) {
return document.defaultView.getComputedStyle(el, null)[property];
}
/**
* Test if the element has opacity display or visibility set
*
* @param {HTMLNode} el - The element to examine
* @return {boolean} - Is the property set
*/
function checkHiddenStyle(el) {
return !!['opacity', 'display', 'visibility'].filter(function check(prop) {
return /(0|none|hidden)/.test(getStyle(el, prop));
}).length;
}
/**
* Test if the element has opacity overflow set
*
* @param {HTMLNode} el - The element to examine
* @return {boolean} - Is the property set
*/
function checkOverflow(el) {
return /(hidden|scroll)/.test(window.getComputedStyle(el, null).getPropertyValue('overflow'));
}
/**
* Is this the body element
*
* @param {HTMLNode} el - An element to examine
* @return {Boolean} Is this the body element
*/
function isBody(el) {
return el.nodeName === 'BODY';
}
/**
*Is the element still attached to the DOM
*
* @param {HTMLNode} el - An element to examine
* @return {Boolean} Is the element still attached to the DOM.
*/
function isAttached(el) {
return document.documentElement.contains(el);
}
/**
* Determine if this element is hidden by its parent by offset or overflow
*
* @param {HTMLElement} el - The element under test
* @return {Boolean} Is the element hidden by its parent
*/
function isOffsetHidden(el) {
var elBox = el.getBoundingClientRect();
var pBox = el.parentElement.getBoundingClientRect();
return elBox.top > pBox.bottom ||
elBox.bottom < pBox.top ||
elBox.left > pBox.right ||
elBox.right < pBox.left;
}
// export public API
module.exports = {
isHidden: isHidden
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment