有没有一种有效的方法来判断DOM元素(在HTML文档中)当前是否可见(显示在视口中)?
(问题是针对Firefox的。)
有没有一种有效的方法来判断DOM元素(在HTML文档中)当前是否可见(显示在视口中)?
(问题是针对Firefox的。)
我使用此功能(因为大多数时候不需要x,所以它仅检查y是否在屏幕上)
function elementInViewport(el) {
var elinfo = {
"top":el.offsetTop,
"height":el.offsetHeight,
};
if (elinfo.top + elinfo.height < window.pageYOffset || elinfo.top > window.pageYOffset + window.innerHeight) {
return false;
} else {
return true;
}
}
这里所有的答案都在确定该元素是否完全包含在视口中,而不仅仅是以某种方式可见。例如,如果视图底部仅可见图像的一半,则考虑到该“外部”,此处的解决方案将失败。
我有一个用例,其中我通过进行了延迟加载IntersectionObserver
,但是由于在弹出过程中发生了动画,因此我不想观察页面加载时已经相交的任何图像。为此,我使用了以下代码:
const bounding = el.getBoundingClientRect();
const isVisible = (0 < bounding.top && bounding.top < (window.innerHeight || document.documentElement.clientHeight)) ||
(0 < bounding.bottom && bounding.bottom < (window.innerHeight || document.documentElement.clientHeight));
基本上,这是在检查视口中的上下边界是否独立。另一端可能在外面,但是只要一端在里面,它至少部分是“可见的”。
这是一个告诉元素在父元素的当前视口中是否可见的函数:
function inParentViewport(el, pa) {
if (typeof jQuery === "function"){
if (el instanceof jQuery)
el = el[0];
if (pa instanceof jQuery)
pa = pa[0];
}
var e = el.getBoundingClientRect();
var p = pa.getBoundingClientRect();
return (
e.bottom >= p.top &&
e.right >= p.left &&
e.top <= p.bottom &&
e.left <= p.right
);
}
更好的解决方案:
function getViewportSize(w) {
var w = w || window;
if(w.innerWidth != null)
return {w:w.innerWidth, h:w.innerHeight};
var d = w.document;
if (document.compatMode == "CSS1Compat") {
return {
w: d.documentElement.clientWidth,
h: d.documentElement.clientHeight
};
}
return { w: d.body.clientWidth, h: d.body.clientWidth };
}
function isViewportVisible(e) {
var box = e.getBoundingClientRect();
var height = box.height || (box.bottom - box.top);
var width = box.width || (box.right - box.left);
var viewport = getViewportSize();
if(!height || !width)
return false;
if(box.top > viewport.h || box.bottom < 0)
return false;
if(box.right < 0 || box.left > viewport.w)
return false;
return true;
}
IMO尽可能简单:
function isVisible(elem) {
var coords = elem.getBoundingClientRect();
return Math.abs(coords.top) <= coords.height;
}
作为Element.getBoundingClientRect()的支持,最简单的解决方案已变得完美:
function isInView(el) {
let box = el.getBoundingClientRect();
return box.top < window.innerHeight && box.bottom >= 0;
}
在Android上放大Google Chrome时,最不能接受的答案无效。结合Dan的answer,要在Android 上使用Chrome,必须使用visualViewport。以下示例仅考虑垂直检查,并使用jQuery作为窗口高度:
var Rect = YOUR_ELEMENT.getBoundingClientRect();
var ElTop = Rect.top, ElBottom = Rect.bottom;
var WindowHeight = $(window).height();
if(window.visualViewport) {
ElTop -= window.visualViewport.offsetTop;
ElBottom -= window.visualViewport.offsetTop;
WindowHeight = window.visualViewport.height;
}
var WithinScreen = (ElTop >= 0 && ElBottom <= WindowHeight);
我认为这是一种更实用的方法。 Dan的答案在递归上下文中不起作用。
当您的元素位于其他可滚动div内时,此功能通过递归测试直到HTML标记的任何级别来解决该问题,并在第一个false处停止。
/**
* fullVisible=true only returns true if the all object rect is visible
*/
function isReallyVisible(el, fullVisible) {
if ( el.tagName == "HTML" )
return true;
var parentRect=el.parentNode.getBoundingClientRect();
var rect = arguments[2] || el.getBoundingClientRect();
return (
( fullVisible ? rect.top >= parentRect.top : rect.bottom > parentRect.top ) &&
( fullVisible ? rect.left >= parentRect.left : rect.right > parentRect.left ) &&
( fullVisible ? rect.bottom <= parentRect.bottom : rect.top < parentRect.bottom ) &&
( fullVisible ? rect.right <= parentRect.right : rect.left < parentRect.right ) &&
isReallyVisible(el.parentNode, fullVisible, rect)
);
};
我在这里遇到的所有答案仅检查该元素是否位于当前视口内。但这并不意味着它是可见的。
如果给定元素位于内容溢出的div内并且滚动到视图之外怎么办?
为了解决这个问题,您必须检查该元素是否包含在所有父元素中。
我的解决方案正是这样做的:
它还允许您指定必须可见的元素数量。
Element.prototype.isVisible = function(percentX, percentY){
var tolerance = 0.01; //needed because the rects returned by getBoundingClientRect provide the position up to 10 decimals
if(percentX == null){
percentX = 100;
}
if(percentY == null){
percentY = 100;
}
var elementRect = this.getBoundingClientRect();
var parentRects = [];
var element = this;
while(element.parentElement != null){
parentRects.push(element.parentElement.getBoundingClientRect());
element = element.parentElement;
}
var visibleInAllParents = parentRects.every(function(parentRect){
var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
var visiblePercentageX = visiblePixelX / elementRect.width * 100;
var visiblePercentageY = visiblePixelY / elementRect.height * 100;
return visiblePercentageX + tolerance > percentX && visiblePercentageY + tolerance > percentY;
});
return visibleInAllParents;
};
该解决方案忽略了由于其他事实(例如)元素可能不可见的事实opacity: 0
。
我已经在Chrome和Internet Explorer 11中测试了此解决方案。
我的简短快速版本:
function isElementOutViewport(el){
var rect = el.getBoundingClientRect();
return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
}
和所需的jsFiddle:https ://jsfiddle.net/on1g619L/1/
有一个叫做inview的jQuery插件可以完成这项工作。
我尝试了丹的答案。但是,用于确定边界的代数意味着该元素必须既≤视口大小,又必须完全在视口内部才能获取true
,很容易导致假阴性。如果要确定某个元素是否完全在视口中,则ryanve的答案很接近,但是要测试的元素应与该视口重叠,因此请尝试以下操作:
function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
return rect.bottom > 0 &&
rect.right > 0 &&
rect.left < (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */ &&
rect.top < (window.innerHeight || document.documentElement.clientHeight) /* or $(window).height() */;
}
请参阅使用getBoundingClientRect的边缘源。就像是:
function inViewport (el) {
var r, html;
if ( !el || 1 !== el.nodeType ) { return false; }
html = document.documentElement;
r = el.getBoundingClientRect();
return ( !!r
&& r.bottom >= 0
&& r.right >= 0
&& r.top <= html.clientHeight
&& r.left <= html.clientWidth
);
}
true
如果元素的任何部分在视口中,则返回。
更新:时间在前进,我们的浏览器也在前进。不再推荐使用此技术,如果不需要支持7之前的Internet Explorer版本,则应使用Dan的解决方案。
原始解决方案(现已过时):
这将检查该元素在当前视口中是否完全可见:
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth)
);
}
您可以简单地对其进行修改,以确定元素的任何部分在视口中是否可见:
function elementInViewport2(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
这将检查元素是否至少部分在视图中(垂直尺寸):