有没有一种有效的方法来判断DOM元素(在HTML文档中)当前是否可见(显示在视口中 )? css
(问题是指Firefox) html
请参阅使用getBoundingClientRect的边缘源。 就像是: node
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
。 git
更新:时间在前进,咱们的浏览器也在前进。 再也不推荐使用此技术,若是不须要支持IE <7,则应使用下面的@Dan解决方案( https://stackoverflow.com/a/7557433/5628 )。 github
原始解决方案(现已过期): 浏览器
这将检查该元素在当前视口中是否彻底可见: dom
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 ); }
更好的解决方案: 测试
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; }
在现代浏览器中,您可能想查看Intersection Observer API ,它具备如下优势: ui
Intersection Observer正在成为完善的标准,而且已在Chrome 51 +,Edge 15+和Firefox 55+中获得支持,而且正在为Safari开发。 还有一个polyfill可用。
Dan提供的答案存在一些问题,可能使它不适用于某些状况。 他在底部的答案中指出了其中一些问题,即他的代码将对如下元素产生误报:
clip
属性隐藏的元素或其子元素 isElementVisible()
这是这些问题的解决方案,下面是测试结果,并对代码的某些部分进行了说明。
function isElementVisible(el) { var rect = el.getBoundingClientRect(), vWidth = window.innerWidth || doc.documentElement.clientWidth, vHeight = window.innerHeight || doc.documentElement.clientHeight, efp = function (x, y) { return document.elementFromPoint(x, y) }; // Return false if it's not in the viewport if (rect.right < 0 || rect.bottom < 0 || rect.left > vWidth || rect.top > vHeight) return false; // Return true if any of its four corners are visible return ( el.contains(efp(rect.left, rect.top)) || el.contains(efp(rect.right, rect.top)) || el.contains(efp(rect.right, rect.bottom)) || el.contains(efp(rect.left, rect.bottom)) ); }
经过测试: http : //jsfiddle.net/AndyE/cAY8c/
结果:
可是,此方法并不是没有其自身的局限性。 例如,即便在前面的元素实际上没有隐藏其任何部分的状况下,使用比同一位置的另外一个元素更低的z-index测试的元素也将被标识为隐藏。 不过,这种方法在某些状况下仍有其用处,但Dan的解决方案却没法解决。
element.getBoundingClientRect()
和document.elementFromPoint()
都是CSSOM工做草案规范的一部分,而且至少在IE 6和更高版本以及大多数台式机浏览器中都获得了长期支持(尽管并不是彻底如此)。 有关更多信息,请参见这些功能的Quirksmode 。
contains()
用于查看document.elementFromPoint()
返回的元素是不是咱们正在测试可见性的元素的子节点。 若是返回的元素是同一元素,则它也返回true。 这只会使检查更可靠。 全部主要浏览器均支持该功能,Firefox 9.0是它们最后添加的浏览器。 要得到较早的Firefox支持,请查看此答案的历史记录。
若是要在元素周围测试更多点的可见性(例如,确保元素覆盖率不超过50%),则无需花费太多时间来调整答案的最后一部分。 可是请注意,若是检查每一个像素以确保其100%可见,这可能会很是慢。
我尝试了Dan的答案, 可是用于肯定范围的代数意味着该元素必须既≤视口大小,又必须彻底在视口内才能获得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() */; }