(HTMLドキュメント内の)DOM要素が現在表示されている( viewport に表示されている)かどうかを判断するための効率的な方法はありますか?
(質問はFirefoxに関するものです)
更新: 時間が近づいているので、私たちのブラウザもそうです。 このテクニックは推奨されなくなりました そしてIE <7をサポートする必要がないなら以下の@ Danの解決法( https://stackoverflow.com/a/7557433/5628 )を使うべきです。
オリジナルの解決策(現在は時代遅れ):
これは、要素が現在のビューポートに完全に表示されているかどうかを確認します。
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
);
}
今 ほとんどのブラウザ support getBoundingClientRect method、これはベストプラクティスとなっています。 非常に遅い 、 正確ではない および いくつかのバグがあります .
正しいと選択された解決策は ほとんど正確ではありません です。 もっと読む そのバグについて。
このソリューションは、IE7 +、iOS5 + Safari、Android2 +、Blackberry、Opera Mobile、およびIE Mobileでテストされています。 10。
function isElementInViewport (el) {
//special bonus for those using jQuery
if (typeof jQuery === "function" && el instanceof jQuery) {
el = el[0];
}
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */
);
}
あなたはそれが呼び出された瞬間に上記の関数が正しい答えを返すことを確認することができますが、イベントとして追跡要素の可視性についてはどうですか?
以下のコードを<body>
タグの末尾に配置します。
function onVisibilityChange(el, callback) {
var old_visible;
return function () {
var visible = isElementInViewport(el);
if (visible != old_visible) {
old_visible = visible;
if (typeof callback == 'function') {
callback();
}
}
}
}
var handler = onVisibilityChange(el, function() {
/* your code go here */
});
//jQuery
$(window).on('DOMContentLoaded load resize scroll', handler);
/* //non-jQuery
if (window.addEventListener) {
addEventListener('DOMContentLoaded', handler, false);
addEventListener('load', handler, false);
addEventListener('scroll', handler, false);
addEventListener('resize', handler, false);
} else if (window.attachEvent) {
attachEvent('onDOMContentLoaded', handler); // IE9+ :(
attachEvent('onload', handler);
attachEvent('onscroll', handler);
attachEvent('onresize', handler);
}
*/
DOMを変更した場合は、もちろん要素の可視性も変わる可能性があります。
ガイドラインとよくある落とし穴:
ページズームやモバイルデバイスのピンチを追跡する必要があるかもしれません。 jQueryは zoom/pinch cross browserを処理するべきで、そうでなければ first または second リンクは助けになるはずです。
DOM を変更すると、要素の可視性に影響する可能性があります。あなたはそれを制御し、手動でhandler()
を呼び出すべきです。残念ながら、クロスブラウザのonrepaint
イベントはありません。その一方で、要素の可視性を変更する可能性があるDOMの変更に対してのみ最適化や再チェックを行うことができます。
これまでにない jQueryの内部で使用する $(document).ready() のみ、 CSSは適用されていないことを保証 現時点ではあなたのコードはハードドライブ上のあなたのCSSとローカルに連携することができますが、一度リモートサーバーに置かれると失敗します。
DOMContentLoaded
が起動された後、 スタイルが適用されます しかし、 イメージはまだロードされていません 。そのため、window.onload
イベントリスナを追加する必要があります。
ズーム/ピンチイベントはまだ捕捉できません。
最後の手段は次のようなコードです。
/* TODO: this looks like a very bad code */
setInterval(handler, 600);
Webページのタブがアクティブで表示されているかどうかを気にする場合は、すばらしい機能 pageVisibiliy HTML5 APIを使用できます。
TODO:このメソッドは2つの状況を処理しません。
z-index
を使ったオーバーラップ要素のコンテナでoverflow-scroll
を使う
何か新しいことを試してみてください https://pawelgrzybek.com/the-intersection-observer-api-explained/ /
最近のブラウザでは、 Intersection Observer API を調べてみるとよいでしょう。
Intersection Observerは、本格的な標準になりつつあり、すでにChrome 51以降、Edge 15以降、およびFirefox 55以降でサポートされており、Safari用に開発中です。 polyfill availableもあります。
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))
);
}
そしてその結果:
しかしながら、この方法はそれ自身の制限がないわけではない。たとえば、同じ場所にある別の要素よりも低いzインデックスでテストされている要素は、前面の要素が実際にはその一部を隠していなくても、隠しとして識別されます。それでも、この方法には、Danの解決方法ではカバーできない用途があります。
element.getBoundingClientRect()
とdocument.elementFromPoint()
は両方ともCSSOMワーキングドラフト仕様の一部であり、少なくともIE 6以降およびmostデスクトップブラウザで(完全ではありませんが)長い間サポートされています。詳しくは これらの関数の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() */;
}
公共サービスとして:
正しい計算(特に携帯電話の画面では、要素はwindowになります)、およびjQueryテストの正しいこと、およびisElementPartiallyInViewportを追加したことに対するDanの答え:
ところで、window.innerWidthとdocument.documentElement.clientWidthの間の の差 は、clientWidth/clientHeightにはスクロールバーが含まれていないのに対し、window.innerWidth/Heightには含まれていません。
function isElementPartiallyInViewport(el)
{
//special bonus for those using jQuery
if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];
var rect = el.getBoundingClientRect();
// DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
var windowWidth = (window.innerWidth || document.documentElement.clientWidth);
// http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);
return (vertInView && horInView);
}
// http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
function isElementInViewport (el)
{
//special bonus for those using jQuery
if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];
var rect = el.getBoundingClientRect();
var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
var windowWidth = (window.innerWidth || document.documentElement.clientWidth);
return (
(rect.left >= 0)
&& (rect.top >= 0)
&& ((rect.left + rect.width) <= windowWidth)
&& ((rect.top + rect.height) <= windowHeight)
);
}
function fnIsVis(ele)
{
var inVpFull = isElementInViewport(ele);
var inVpPartial = isElementPartiallyInViewport(ele);
console.clear();
console.log("Fully in viewport: " + inVpFull);
console.log("Partially in viewport: " + inVpPartial);
}
テストケース
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Test</title>
<!--
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script src="scrollMonitor.js"></script>
-->
<script type="text/javascript">
function isElementPartiallyInViewport(el)
{
//special bonus for those using jQuery
if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];
var rect = el.getBoundingClientRect();
// DOMRect { x: 8, y: 8, width: 100, height: 100, top: 8, right: 108, bottom: 108, left: 8 }
var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
var windowWidth = (window.innerWidth || document.documentElement.clientWidth);
// http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
var vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
var horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);
return (vertInView && horInView);
}
// http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
function isElementInViewport (el)
{
//special bonus for those using jQuery
if (typeof jQuery !== 'undefined' && el instanceof jQuery) el = el[0];
var rect = el.getBoundingClientRect();
var windowHeight = (window.innerHeight || document.documentElement.clientHeight);
var windowWidth = (window.innerWidth || document.documentElement.clientWidth);
return (
(rect.left >= 0)
&& (rect.top >= 0)
&& ((rect.left + rect.width) <= windowWidth)
&& ((rect.top + rect.height) <= windowHeight)
);
}
function fnIsVis(ele)
{
var inVpFull = isElementInViewport(ele);
var inVpPartial = isElementPartiallyInViewport(ele);
console.clear();
console.log("Fully in viewport: " + inVpFull);
console.log("Partially in viewport: " + inVpPartial);
}
// var scrollLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft,
// var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
</script>
</head>
<body>
<div style="display: block; width: 2000px; height: 10000px; background-color: green;">
<br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br />
<input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />
<br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br />
<div style="background-color: crimson; display: inline-block; width: 800px; height: 500px;" ></div>
<div id="myele" onclick="fnIsVis(this);" style="display: inline-block; width: 100px; height: 100px; background-color: hotpink;">
t
</div>
<br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br />
<input type="button" onclick="fnIsVis(document.getElementById('myele'));" value="det" />
</div>
<!--
<script type="text/javascript">
var element = document.getElementById("myele");
var watcher = scrollMonitor.create( element );
watcher.lock();
watcher.stateChange(function() {
console.log("state changed");
// $(element).toggleClass('fixed', this.isAboveViewport)
});
</script>
-->
</body>
</html>
仕事をする inview というjQueryプラグインがあります。
getBoundingClientRect を使用する verge のソースを参照してください。それはのようなものです:
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
);
}
any 要素の一部がビューポート内にある場合はtrue
を返します。
私の短くて速いバージョン。
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/ /
利用可能な機能のjQuery
中心のバージョンがなかったのは厄介です。私が出会ったとき Danの解決策jQuery
OOスタイルでプログラムしたい人のために何かを提供する機会をスパイしました。必ず上にスクロールして、Danのコードに支持票を残してください。その素敵でてきぱきと私のための魅力のように動作します。
バダビングバダブーム
$.fn.inView = function(){
if(!this.length) return false;
var rect = this.get(0).getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
//additional examples for other use cases
//true false whether an array of elements are all in view
$.fn.allInView = function(){
var all = [];
this.forEach(function(){
all.Push( $(this).inView() );
});
return all.indexOf(false) === -1;
};
//only the class elements in view
$('.some-class').filter(function(){
return $(this).inView();
});
//only the class elements not in view
$('.some-class').filter(function(){
return !$(this).inView();
});
用法
$(window).on('scroll',function(){
if( $('footer').inView() ) {
// do cool stuff
}
});
ここで認められている答えは、ほとんどのユースケースでは非常に複雑です。このコードは(JQueryを使用して)うまく機能し、完全に見える要素と部分的に見える要素を区別します。
var element = $("#element");
var topOfElement = element.offset().top;
var bottomOfElement = element.offset().top + element.outerHeight(true);
var $window = $(window);
$window.bind('scroll', function() {
var scrollTopPosition = $window.scrollTop()+$window.height();
var windowScrollTop = $window.scrollTop()
if( windowScrollTop > topOfElement && windowScrollTop < bottomOfElement) {
// Element is partially visible (above viewable area)
console.log("Element is partially visible (above viewable area)");
}else if( windowScrollTop > bottomOfElement && windowScrollTop > topOfElement ) {
// Element is hidden (above viewable area)
console.log("Element is hidden (above viewable area)");
}else if( scrollTopPosition < topOfElement && scrollTopPosition < bottomOfElement ) {
// Element is hidden (below viewable area)
console.log("Element is hidden (below viewable area)");
}else if( scrollTopPosition < bottomOfElement && scrollTopPosition > topOfElement ) {
// Element is partially visible (below viewable area)
console.log("Element is partially visible (below viewable area)");
}else{
// Element is completely visible
console.log("Element is completely visible");
}
});
私がここで遭遇したすべての答えは、要素が現在のビューポートの内側に配置されているであるかどうかをチェックするだけです。しかし、それは見えることを意味するのではありませんです。
与えられた要素があふれた内容の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でテストしました。
新しい Intersection Observer API はこの問題に直接対処します。
Safari、Opera、およびIEはまだサポートしていないため、このソリューションではポリフィルが必要になります。 (ポリフィルは溶液に含まれている)。
この解決策では、対象となる(観察される)視野外のボックスがあります。表示されると、ヘッダーの上部にあるボタンが非表示になります。ボックスがビューから出ると表示されます。
const buttonToHide = document.querySelector('button');
const hideWhenBoxInView = new IntersectionObserver((entries) => {
if (entries[0].intersectionRatio <= 0) { // If not in view
buttonToHide.style.display = "inherit";
} else {
buttonToHide.style.display = "none";
}
});
hideWhenBoxInView.observe(document.getElementById('box'));
header {
position: fixed;
top: 0;
width: 100vw;
height: 30px;
background-color: lightgreen;
}
.wrapper {
position: relative;
margin-top: 600px;
}
#box {
position: relative;
left: 175px;
width: 150px;
height: 135px;
background-color: lightblue;
border: 2px solid;
}
<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<header>
<button>NAVIGATION BUTTON TO HIDE</button>
</header>
<div class="wrapper">
<div id="box">
</div>
</div>
これはもっと機能的な方法だと思います。ダンの答えは再帰的には機能しません。
この関数は、あなたの要素が他のスクロール可能なdivの内側にあるとき、HTMLタグより上のレベルを再帰的にテストすることによって問題を解決し、最初の偽で停止します。
/**
* 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)
);
};
上記の@ danの解決策( https://stackoverflow.com/a/7557433/5628 )に基づいて、同じページで複数回使用するのが簡単になるように、実装を整理しました。
$(function() {
$(window).on('load resize scroll', function() {
addClassToElementInViewport($('.bug-icon'), 'animate-bug-icon');
addClassToElementInViewport($('.another-thing'), 'animate-thing');
// ???? repeat as needed ...
});
function addClassToElementInViewport(element, newClass) {
if (inViewport(element)) {
element.addClass(newClass);
}
}
function inViewport(element) {
if (typeof jQuery === "function" && element instanceof jQuery) {
element = element[0];
}
var elementBounds = element.getBoundingClientRect();
return (
elementBounds.top >= 0 &&
elementBounds.left >= 0 &&
elementBounds.bottom <= $(window).height() &&
elementBounds.right <= $(window).width()
);
}
});
私が使っている方法は、要素がスクロールして表示されるときに、CSSのキーフレームアニメーションをトリガーするクラスを追加することです。それはかなり簡単で、あなたがページ上で条件付きでアニメ化するために10以上のものが好きになったときに特にうまくいきます。
それが役に立てば幸い!
目に見えることによってあなたが意味するものによります。スクロール位置が与えられたときに、それが現在ページに表示されているということであれば、要素y offsetと現在のスクロール位置に基づいて計算できます。
それはIMOを得ることができるのと同じくらい簡単:
function isVisible(elem) {
var coords = elem.getBoundingClientRect();
return Math.abs(coords.top) <= coords.height;
}
私のために働いてきた簡単で小さな解決策。
例 オーバーフロースクロールがある親要素にその要素が表示されているかどうかを確認します。
$(window).on('scroll', function () {
var container = $('#sidebar');
var containerHeight = container.height();
var scrollPosition = $('#row1').offset().top - container.offset().top;
if (containerHeight < scrollPosition) {
console.log('not visible');
} else {
console.log('visible');
}
})
これが私の解決策です。要素がスクロール可能なコンテナの中に隠れていてもうまくいきます。
これがデモです (ウィンドウのサイズを変更してみてください)
var visibleY = function(el){
var top = el.getBoundingClientRect().top, rect, el = el.parentNode;
do {
rect = el.getBoundingClientRect();
if (top <= rect.bottom === false)
return false;
el = el.parentNode;
} while (el != document.body);
// Check its within the document viewport
return top <= document.documentElement.clientHeight;
};
Y軸に表示されるかどうかを確認するだけで済みました(スクロールするAjaxの場合は、さらにレコードを読み込む機能があります)。
私は同じ質問をして、getBoundingClientRect()を使ってそれを考え出しました。このコードは完全に '総称'であり、それが機能するために一度だけ書かれる必要があります(あなたが知りたい各要素についてそれを書き出す必要はありません)。このコードは、ビューポート内で垂直方向であるかどうかを確認するためにのみチェックされます 水平方向ではなく 。この場合、変数(配列)の 'elements'はビューポート内で縦方向に並んでいることを確認しているすべての要素を保持しているので、必要な要素をどこでもつかんでそこに格納します。 'for loop'は、各要素をループして、ビューポート内で縦方向に並んでいるかどうかを確認します。このコードは 毎回 ユーザーがスクロールするように実行します。 getBoudingClientRect()。topがビューポートの3/4より小さい場合(要素はビューポート内の4分の1)、「ビューポート内」として登録されます。コードは一般的なものなので、ビューポートに「どの」要素があるのかを知りたいでしょう。それを見つけるために、カスタム属性、ノード名、ID、クラス名などでそれを決定できます。これが私のコードです(うまく動かない場合は教えてください、それはIE 11、FireFox 40.0.3、Chromeバージョン45.0.2454.85 m、Opera 31.0.1889.174、およびWindows 10搭載のEdgeでテストされています、(まだSafariではありません))...
//scrolling handlers...
window.onscroll = function(){
var elements = document.getElementById('whatever').getElementsByClassName('whatever');
for(var i = 0; i != elements.length; i++)
{
if(elements[i].getBoundingClientRect().top <= window.innerHeight*0.75 && elements[i].getBoundingClientRect().top > 0)
{
console.log(elements[i].nodeName + ' ' + elements[i].className + ' ' + elements[i].id + ' is in the viewport; proceed with whatever code you want to do here.');
}
};
これが誰かに役立つことを願っています:-)
より良い解決策:
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;
}
要素が少なくとも部分的に表示されているかどうかを確認します(垂直方向の寸法)。
function inView(element) {
var box = element.getBoundingClientRect();
return inViewBox(box);
}
function inViewBox(box) {
return ((box.bottom < 0) || (box.top > getWindowSize().h)) ? false : true;
}
function getWindowSize() {
return { w: document.body.offsetWidth || document.documentElement.offsetWidth || window.innerWidth, h: document.body.offsetHeight || document.documentElement.offsetHeight || window.innerHeight}
}
Element.getBoundingClientRect() の compatibility が完全になったため、最も簡単なソリューション:
function inView(el) {
let box = el.getBoundingClientRect();
return box.top < window.innerHeight && box.bottom >= 0;
}
これは、要素が parent 要素の現在のビューポートに表示されているかどうかを通知する関数です。
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
);
}