Last active
November 27, 2023 11:05
-
-
Save c-kick/59eb52a762b014539c00678d4bac6b09 to your computer and use it in GitHub Desktop.
Check if an element is visible
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** isVisible | |
* | |
* Determines whether an element is visible within the (specified, or Window) viewport. Executes the callback based | |
* on that result. The callback is called with three parameters: | |
* - visible: a boolean that's true if ANY pixels of the element are visible | |
* - fullyVisible: a boolean that's true if the ENTIRE element fits the viewport, and thus is wholly visible | |
* - the element's bounding box, including 'pageY' and 'pageX' which contain the element's position as relative to | |
* the whole document. Useful for scrolling into view, | |
* | |
* The viewport can either be omitted, specified partially or completely. | |
* | |
* Usage: isVisible(myElement, callback, {viewport object}); | |
* | |
* @param {Element} element - The element to check for visibility. | |
* @param {Function} callback - The callback function to execute when done checking. | |
* @param {Object} [vp] - Object (optional) containing top, bottom, left and right offsets of the viewport to check against - falls back to the Window if not provided. | |
*/ | |
export function isVisible(element, callback, vp = {}) { | |
if (!(element instanceof Element)) { | |
throw new TypeError('Not a valid node'); | |
} | |
if (typeof element.getBoundingClientRect === 'function') { | |
const rect = element.getBoundingClientRect(); | |
const scrollTop = window.pageYOffset || document.documentElement.scrollTop; | |
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; | |
const clientTop = document.documentElement.clientTop; | |
const clientLeft = document.documentElement.clientLeft; | |
rect.pageY = rect.top + scrollTop - clientTop; | |
rect.pageX = rect.left + scrollLeft - clientLeft; | |
const viewport = { | |
top: typeof vp.top !== 'undefined' ? vp.top : 0, | |
bottom: typeof vp.bottom !== 'undefined' ? vp.bottom : window.innerHeight || document.documentElement.clientHeight, | |
left: typeof vp.left !== 'undefined' ? vp.left : 0, | |
right: typeof vp.right !== 'undefined' ? vp.right : window.innerWidth || document.documentElement.clientWidth, | |
}; | |
const fullyVisible = ( | |
(rect.height > 0 || rect.width > 0) && | |
rect.bottom < viewport.bottom && | |
rect.right < viewport.right && | |
rect.top > viewport.top && | |
rect.left > viewport.left | |
); | |
const visible = ( | |
(rect.height > 0 || rect.width > 0) && | |
rect.bottom >= 0 && | |
rect.top <= viewport.bottom && | |
((rect.right > viewport.left && rect.right <= viewport.right) || (rect.left < viewport.right && rect.left >= viewport.left)) | |
) | |
if (typeof callback === 'function') { | |
callback.call(this, visible, fullyVisible, rect); | |
} | |
} else { | |
console.error('Can\'t check visibility for', typeof this, this); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment