В конце концов, ни один из примеров меня не устраивает, поэтому я написал свой собственный.
Тесты (без поддержки Internet Explorer filter:alpha
):
а) Проверьте, не скрыт ли документ
b) Проверьте, имеет ли элемент нулевую ширину / высоту / непрозрачность или display:none
/ visibility:hidden
во встроенных стилях
c) Проверьте, не скрыт ли центр (также потому что он быстрее, чем тестирование каждого пикселя / угла) элемента другим элементом (и всеми предками, например: overflow:hidden
/ scroll / one element over enother) или экраном края
d) Проверить, имеет ли элемент нулевую ширину / высоту / непрозрачность или display:none
/ видимость: скрыто в вычисляемых стилях (среди всех предков)
Проверено на
Android 4.4 (собственный браузер / Chrome / Firefox), Firefox (Windows / Mac), Chrome (Windows / Mac), Opera (Windows Presto / Mac Webkit), Internet Explorer (Internet Explorer 5- 11 режимов документа + Internet Explorer 8 на виртуальной машине), Safari (Windows / Mac / iOS)
var is_visible = (function () {
var x = window.pageXOffset ? window.pageXOffset + window.innerWidth - 1 : 0,
y = window.pageYOffset ? window.pageYOffset + window.innerHeight - 1 : 0,
relative = !!((!x && !y) || !document.elementFromPoint(x, y));
function inside(child, parent) {
while(child){
if (child === parent) return true;
child = child.parentNode;
}
return false;
};
return function (elem) {
if (
document.hidden ||
elem.offsetWidth==0 ||
elem.offsetHeight==0 ||
elem.style.visibility=='hidden' ||
elem.style.display=='none' ||
elem.style.opacity===0
) return false;
var rect = elem.getBoundingClientRect();
if (relative) {
if (!inside(document.elementFromPoint(rect.left + elem.offsetWidth/2, rect.top + elem.offsetHeight/2),elem)) return false;
} else if (
!inside(document.elementFromPoint(rect.left + elem.offsetWidth/2 + window.pageXOffset, rect.top + elem.offsetHeight/2 + window.pageYOffset), elem) ||
(
rect.top + elem.offsetHeight/2 < 0 ||
rect.left + elem.offsetWidth/2 < 0 ||
rect.bottom - elem.offsetHeight/2 > (window.innerHeight || document.documentElement.clientHeight) ||
rect.right - elem.offsetWidth/2 > (window.innerWidth || document.documentElement.clientWidth)
)
) return false;
if (window.getComputedStyle || elem.currentStyle) {
var el = elem,
comp = null;
while (el) {
if (el === document) {break;} else if(!el.parentNode) return false;
comp = window.getComputedStyle ? window.getComputedStyle(el, null) : el.currentStyle;
if (comp && (comp.visibility=='hidden' || comp.display == 'none' || (typeof comp.opacity !=='undefined' && comp.opacity != 1))) return false;
el = el.parentNode;
}
}
return true;
}
})();
Как использовать:
is_visible(elem) // boolean