有沒有一種有效的方法來判斷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() */; }