DOM 要素が現在のビューポートに表示されているかどうかを確認するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/123999

質問

DOM 要素 (HTML ドキュメント内) が現在表示されているかどうか ( ビューポート)?

(質問はFirefoxに関するものです)

役に立ちましたか?

解決

アップデート: 時は流れ、ブラウザも進化していきます。 このテクニックは推奨されなくなりました そして、以下の@Danのソリューションを使用する必要があります(https://stackoverflow.com/a/7557433/5628) IE<7 をサポートする必要がない場合。

元のソリューション (現在は古い):

これにより、要素が現在のビューポートに完全に表示されているかどうかがチェックされます。

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
  );
}

他のヒント

ほとんどのブラウザ サポート getBoundingClientRect この方法はベストプラクティスとなっています。古い答えを使用するのは、 非常に遅い, 正確ではない そして いくつかのバグがあります.

正解として選択された解決策は、 正確なことはほとんどありません. 。あなたはできる 続きを読む そのバグについて。


このソリューションは、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 が処理する必要がある ズーム/ピンチ クロスブラウザ、それ以外の場合 初め または 2番 リンクが役立つはずです。

もし、あんたが DOM を変更する, 、要素の可視性に影響を与える可能性があります。あなたはそれを制御して電話する必要があります handler() 手動で。残念ながら、クロスブラウザはありません onrepaint イベント。一方、これにより、要素の可視性を変更する可能性のある DOM 変更に対してのみ最適化を行って再チェックを実行できます。

決して決して jQuery内で使用します $(ドキュメント).ready() ただ、なぜなら CSS が適用されているという保証はありません この瞬間に。コードはハード ドライブ上の CSS を使用してローカルで動作しますが、リモート サーバーに配置すると失敗します。

DOMContentLoaded 解雇され、 スタイルが適用される, 、 しかし 画像はまだ読み込まれていません. 。したがって、追加する必要があります window.onload イベントリスナー。

ズーム/ピンチイベントはまだキャッチできません。

最後の手段としては、次のコードが考えられます。

/* TODO: this looks like a very bad code */
setInterval(handler, 600); 

すごい機能が使えるよ ページの可視性 Web ページのタブがアクティブで表示されているかどうかを気にする場合は、HTML5 API を使用します。

TODO:このメソッドは次の 2 つの状況を処理しません。

アップデート

最新のブラウザでは、次のことを確認してください。 交差点オブザーバー API これにより、次のような利点が得られます。

  • スクロール イベントをリッスンするよりも優れたパフォーマンス
  • クロスドメイン iframe で動作します
  • 要素が別の要素を妨害/交差しているかどうかを判断できます

Intersection Observer は本格的な標準になる途上にあり、すでに Chrome 51 以降、Edge 15 以降、Firefox 55 以降でサポートされており、Safari 用に開発中です。もあります ポリフィル 利用可能。


前の回答

いくつかの問題があります ダンが提供した回答 そのため、状況によっては不適切なアプローチになる可能性があります。これらの問題のいくつかは、下部近くの彼の回答で指摘されており、彼のコードは次の要素に対して誤検知を与えるということです。

  • テスト対象の要素の前にある別の要素によって隠されています
  • 親要素または祖先要素の表示領域の外側
  • CSS を使用して非表示にした要素またはその子 clip 財産

これらの制限は、次の結果で実証されています。 簡単なテスト:

Failed test, using isElementInViewport

ソリューション: 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/

そして結果:

Passed test, using isElementVisible

その他の注意事項

ただし、この方法にも制限がないわけではありません。たとえば、同じ位置にある別の要素よりも低い z インデックスでテストされている要素は、前の要素が実際にその要素のどの部分も隠していない場合でも、非表示として識別されます。それでも、この方法には、Dan のソリューションではカバーされていない場合があります。

両方 element.getBoundingClientRect() そして document.elementFromPoint() CSSOM Working Draft 仕様の一部であり、少なくとも IE 6 以降でサポートされています。 ほとんど 長い間デスクトップブラウザを使用していました(完全ではありませんが)。見る これらの関数の Quirksmode 詳細については。

contains() によって返された要素かどうかを確認するために使用されます。 document.elementFromPoint() は、可視性をテストしている要素の子ノードです。返された要素が同じ要素である場合にも true を返します。これにより、チェックがより堅牢になるだけです。これはすべての主要なブラウザでサポートされており、Firefox 9.0 が最後に追加されました。古い Firefox のサポートについては、この回答の履歴を確認してください。

要素の周囲のより多くの点の可視性をテストする場合、つまり、要素がたとえば 50% を超えて覆われていないことを確認する場合、答えの最後の部分を調整するのにそれほど時間はかかりません。ただし、すべてのピクセルをチェックして 100% 表示されていることを確認すると、処理が非常に遅くなる可能性があることに注意してください。

私は試した ダンの答え しかし 境界を決定するために使用される代数は、取得するには要素がビューポート サイズ以下であり、完全にビューポート内にある必要があることを意味します。 true, 、簡単に偽陰性が発生します。要素がビューポート内にあるかどうかを確認したい場合は、次のようにします。 ライアンベの答え は近いですが、テスト対象の要素はビューポートと重なるはずなので、これを試してください。

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() */;
}

公共サービスとして:
Dan の答えは、正しい計算 (特に携帯電話の画面では、要素は > ウィンドウである可能性があります)、正しい jQuery テスト、および isElementPartiallyInViewport の追加です。

ちなみに、 違い 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>

というjQueryプラグインがあります ビューで それは仕事をする

のソースを参照してください 寸前, を使用します。 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 もし どれでも 要素の一部がビューポートに表示されます。

私の短くて速いバージョン。

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 利用可能な機能の中心バージョン。出会ったとき ダンの解決策 私は、プログラミングを好む人たちに何かを提供する機会を見つけました。 jQuery ○○スタイル。必ず上にスクロールして、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 でテストしました。

新しい 交差点オブザーバー 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>

これはより機能的な方法だと思います。ダンの答えは再帰的なコンテキストでは機能しません。

この関数は、HTML タグより上位のレベルを再帰的にテストし、最初の false で停止することで、要素が他のスクロール可能な div 内にある場合の問題を解決します。

/**
 * 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 個以上ある場合に特にうまく機能します。

それが役に立てば幸い!

これが私の解決策です。要素がスクロール可能なコンテナ内に隠されている場合に機能します。

こちらがデモです (ウィンドウのサイズを変更してみてください)

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 のレコード追加機能の場合)。

私にとってうまくいった、簡単で小さな解決策。

オーバーフロー スクロールのある親要素内でその要素が表示されるかどうかを確認したいとします。

$(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');
     }
})

より良い解決策:

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} 
}

私も同じ質問をしましたが、getBoundingClientRect() を使用して解決しました。このコードは完全に「汎用」であり、機能するために一度だけ記述する必要があります (ビューポート内にあることを知りたい要素ごとにコードを書き出す必要はありません)。このコードは、ビューポート内で垂直方向にあるかどうかを確認するだけです。 水平ではない. 。この場合、変数 (配列) 'elements' には、ビューポート内で垂直方向にあることをチェックしているすべての要素が保持されているため、任意の場所に必要な要素を取得して、そこに保存します。「for ループ」は、各要素をループし、ビューポート内で垂直方向に配置されているかどうかを確認します。このコードは実行されます 毎回 ユーザーはスクロールします!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 でテストされています [まだ S​​afari ではありません] )...

//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 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
    );
}

IMO を取得するのはできるだけ簡単です。

function isVisible(elem) {
  var coords = elem.getBoundingClientRect();
  return Math.abs(coords.top) <= coords.height;
}

私はこの関数を使用します(ほとんどの場合、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;
    }

}

同様のチャレンジでは本当に楽しかったです この要点 これはポリフィルを公開します scrollIntoViewIfNeeded().

答えるために必要なカンフーはすべてこのブロック内にあります。

var parent = this.parentNode,
    parentComputedStyle = window.getComputedStyle(parent, null),
    parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
    parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
    overTop = this.offsetTop - parent.offsetTop < parent.scrollTop,
    overBottom = (this.offsetTop - parent.offsetTop + this.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
    overLeft = this.offsetLeft - parent.offsetLeft < parent.scrollLeft,
    overRight = (this.offsetLeft - parent.offsetLeft + this.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
    alignWithTop = overTop && !overBottom;

this は、知りたい要素を指します。つまり、 overTop または overBottom - ドリフトを取得する必要があります...

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top