Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Checks if a DOM element is visible. Takes into consideration its parents and overflow.
var my_element = document.getElementById('my-element');
//-- Returns true/false
my_element.isVisible(my_element);
/**
* Author: Jason Farrell
* Author URI: http://useallfive.com/
*
* Description: Checks if a DOM element is truly visible.
* Package URL: https://github.com/UseAllFive/true-visibility
*/
Element.prototype.isVisible = function() {
'use strict';
/**
* Checks if a DOM element is visible. Takes into
* consideration its parents and overflow.
*
* @param (el) the DOM element to check if is visible
*
* These params are optional that are sent in recursively,
* you typically won't use these:
*
* @param (t) Top corner position number
* @param (r) Right corner position number
* @param (b) Bottom corner position number
* @param (l) Left corner position number
* @param (w) Element width number
* @param (h) Element height number
*/
function _isVisible(el, t, r, b, l, w, h) {
var p = el.parentNode,
VISIBLE_PADDING = 2;
if ( !_elementInDocument(el) ) {
return false;
}
//-- Return true for document node
if ( 9 === p.nodeType ) {
return true;
}
//-- Return false if our element is invisible
if (
'0' === _getStyle(el, 'opacity') ||
'none' === _getStyle(el, 'display') ||
'hidden' === _getStyle(el, 'visibility')
) {
return false;
}
if (
'undefined' === typeof(t) ||
'undefined' === typeof(r) ||
'undefined' === typeof(b) ||
'undefined' === typeof(l) ||
'undefined' === typeof(w) ||
'undefined' === typeof(h)
) {
t = el.offsetTop;
l = el.offsetLeft;
b = t + el.offsetHeight;
r = l + el.offsetWidth;
w = el.offsetWidth;
h = el.offsetHeight;
}
//-- If we have a parent, let's continue:
if ( p ) {
//-- Check if the parent can hide its children.
if ( ('hidden' === _getStyle(p, 'overflow') || 'scroll' === _getStyle(p, 'overflow')) ) {
//-- Only check if the offset is different for the parent
if (
//-- If the target element is to the right of the parent elm
l + VISIBLE_PADDING > p.offsetWidth + p.scrollLeft ||
//-- If the target element is to the left of the parent elm
l + w - VISIBLE_PADDING < p.scrollLeft ||
//-- If the target element is under the parent elm
t + VISIBLE_PADDING > p.offsetHeight + p.scrollTop ||
//-- If the target element is above the parent elm
t + h - VISIBLE_PADDING < p.scrollTop
) {
//-- Our target element is out of bounds:
return false;
}
}
//-- Add the offset parent's left/top coords to our element's offset:
if ( el.offsetParent === p ) {
l += p.offsetLeft;
t += p.offsetTop;
}
//-- Let's recursively check upwards:
return _isVisible(p, t, r, b, l, w, h);
}
return true;
}
//-- Cross browser method to get style properties:
function _getStyle(el, property) {
if ( window.getComputedStyle ) {
return document.defaultView.getComputedStyle(el,null)[property];
}
if ( el.currentStyle ) {
return el.currentStyle[property];
}
}
function _elementInDocument(element) {
while (element = element.parentNode) {
if (element == document) {
return true;
}
}
return false;
}
return _isVisible(this);
};
@loominade

This comment has been minimized.

Copy link

@loominade loominade commented Apr 8, 2015

my_element.isVisible(my_element);

the first parameter is useless isn't it?

@francislavoie

This comment has been minimized.

Copy link

@francislavoie francislavoie commented Nov 18, 2015

I'm having an issue when the el.offsetParent is different from p on line 72, where it returns true because l is a large number. It breaks for me in that case.

@francislavoie

This comment has been minimized.

Copy link

@francislavoie francislavoie commented Nov 18, 2015

As a temporary fix I added el.offsetParent === p && to line 68 to skip that check if the parents are different. Kinda just a workaround but it seems to work for now.

@galipmedia

This comment has been minimized.

Copy link

@galipmedia galipmedia commented Feb 11, 2016

Is it possible to add to this a check if the parent is off screen? like position: absolute; left: -1000; or off to the right, top, bottom?

@ariden83

This comment has been minimized.

Copy link

@ariden83 ariden83 commented Apr 30, 2016

Maybe, it's better to change :

'0' === _getStyle(el, 'opacity') ||

to

'1' !== _getStyle(el, 'opacity') ||

because of everyOne can change opacity

ex: opacity: 0.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.