web-dev-qa-db-de.com

Wie kann ich feststellen, ob ein DOM-Element im aktuellen Ansichtsfenster sichtbar ist?

Gibt es eine effiziente Möglichkeit, festzustellen, ob ein DOM-Element (in einem HTML-Dokument) aktuell sichtbar ist (im viewport angezeigt)?

(Die Frage betrifft Firefox)

807
benzaita

Update: Die Zeit schreitet voran, ebenso unsere Browser. Diese Technik wird nicht mehr empfohlen und Sie sollten @ Dans Lösung unten ( https://stackoverflow.com/a/7557433/5628 ) verwenden, wenn Sie den IE <7 nicht benötigen.

Originallösung (jetzt veraltet):

Dadurch wird geprüft, ob das Element im aktuellen Ansichtsfenster vollständig sichtbar ist:

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

Sie können dies einfach ändern, um festzustellen, ob ein Teil des Elements im Ansichtsfenster sichtbar ist:

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

Jetzt die meisten Browser support getBoundingClientRect Methode, die sich als bewährte Methode erwiesen hat. Die Verwendung einer alten Antwort ist sehr langsam , ist nicht genau und hat mehrere Fehler .

Die als richtig gewählte Lösung ist fast nie genau . Sie können lesen Sie mehr über die Fehler.


Diese Lösung wurde auf IE7 +, iOS5 + Safari, Android2 +, Blackberry, Opera Mobile und IE Mobile getestet 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() */
    );
}

Wie benutzt man:

Sie können sicher sein, dass die oben angegebene Funktion zum Zeitpunkt des Aufrufs die richtige Antwort zurückgibt. Wie sieht es jedoch mit der Sichtbarkeit eines Elements als Ereignis aus?

Fügen Sie den folgenden Code am Ende Ihres <body>-Tags ein:

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

Wenn Sie DOM-Änderungen vornehmen, können sie natürlich die Sichtbarkeit Ihres Elements ändern.

Richtlinien und häufige Fallstricke:

Möglicherweise müssen Sie den Seitenzoom nachverfolgen/das Gerät mit dem mobilen Gerät aufspüren? JQuery sollte mit zoom/pinch cross browser umgehen, ansonsten sollte first oder second link Ihnen helfen. 

Wenn Sie DOM ändern beeinflussen, kann dies die Sichtbarkeit des Elements beeinträchtigen. Sie sollten die Kontrolle übernehmen und handler() manuell aufrufen. Leider haben wir kein Browserübergreifendes onrepaint-Ereignis. Auf der anderen Seite können wir Optimierungen vornehmen und eine erneute Überprüfung nur für DOM-Änderungen durchführen, die die Sichtbarkeit des Elements ändern können.

Never Ever es innerhalb von jQuery $ (document) .ready () verwenden, nur weil es gibt keine Gewährleistungs-CSS in diesem Moment. Ihr Code kann lokal mit Ihrem CSS auf der Festplatte arbeiten, aber wenn Sie sich auf einem Remote-Server befinden, schlägt der Code fehl.

Nachdem DOMContentLoaded ausgelöst wurde, werden Stile angewendet , aber die Bilder werden noch nicht geladen . Also sollten wir den window.onload Ereignis-Listener hinzufügen.

Zoom-/Prise-Event können wir noch nicht fangen.

Der letzte Ausweg könnte der folgende Code sein:

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

Sie können die awesome Feature pageVisibiliy HTML5-API verwenden, wenn Sie darauf achten, ob die Registerkarte Ihrer Webseite aktiv und sichtbar ist.

TODO: Diese Methode behandelt zwei Situationen nicht:

1258
Dan

Aktualisieren

In modernen Browsern sollten Sie die Intersection Observer API ausprobieren, die die folgenden Vorteile bietet:

  • Bessere Leistung als das Abhören von Scroll-Ereignissen
  • Funktioniert in domänenübergreifenden iframes
  • Kann feststellen, ob ein Element ein anderes blockiert/schneidet

Intersection Observer ist auf dem Weg zu einem vollwertigen Standard und wird bereits in Chrome 51+, Edge 15+ und Firefox 55+ unterstützt und wird für Safari entwickelt. Es ist auch ein Polyfill verfügbar.


Vorherige Antwort

Es gibt einige Probleme mit dem Antwort von Dan , die es für einige Situationen möglicherweise ungeeignet macht. Einige dieser Probleme werden in seiner Antwort am unteren Rand hervorgehoben, dass sein Code falsche Elemente für Elemente gibt, die:

  • Versteckt durch ein anderes Element vor dem getesteten Element
  • Außerhalb des sichtbaren Bereichs eines übergeordneten oder Vorfahrenelements
  • Ein Element oder dessen untergeordnete Elemente werden mithilfe der CSS-Eigenschaft clip ausgeblendet

Diese Einschränkungen werden in den folgenden Ergebnissen eines einfachen Tests demonstriert:

Failed test, using isElementInViewport

Die Lösung: isElementVisible()

Hier finden Sie eine Lösung für diese Probleme mit dem Testergebnis und einer Erläuterung einiger Teile des Codes.

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

Bestandenprüfung: _ ​​ http://jsfiddle.net/AndyE/cAY8c/

Und das Ergebnis:

Passed test, using isElementVisible

Zusätzliche Bemerkungen

Diese Methode ist jedoch nicht ohne eigene Einschränkungen. Beispielsweise wird ein Element, das mit einem niedrigeren Z-Index als ein anderes Element an derselben Position getestet wird, als ausgeblendet erkannt, selbst wenn das Element davor keinen Teil des Elements verbirgt. Diese Methode hat jedoch in einigen Fällen ihre Anwendung, die Dans Lösung nicht abdeckt.

Sowohl element.getBoundingClientRect() als auch document.elementFromPoint() sind Teil der CSSOM Working Draft-Spezifikation und werden mindestens in IE 6 und höher und den meisten Desktop-Browsern lange Zeit (wenn auch nicht perfekt) unterstützt. Weitere Informationen finden Sie unter Quirksmode für diese Funktionen .

contains() wird verwendet, um festzustellen, ob das von document.elementFromPoint() zurückgegebene Element ein untergeordneter Knoten des Elements ist, das auf Sichtbarkeit getestet wird. Sie gibt auch true zurück, wenn das zurückgegebene Element dasselbe Element ist. Dies macht den Check nur noch robuster. Es wird in allen gängigen Browsern unterstützt. Firefox 9.0 ist der letzte, der es hinzugefügt hat. Überprüfen Sie für ältere Firefox-Unterstützung den Verlauf dieser Antwort.

Wenn Sie mehr Punkte rund um das Element auf Sichtbarkeit testen möchten, dh um sicherzustellen, dass das Element nicht mehr als 50% ist, müssen Sie den letzten Teil der Antwort nicht anpassen. Beachten Sie jedoch, dass es wahrscheinlich sehr langsam sein würde, wenn Sie jedes Pixel überprüfen, um sicherzustellen, dass es zu 100% sichtbar ist.

143
Andy E

Ich habe versucht, Dans Antwort. Die Algebra, die zur Bestimmung der Grenzen verwendet wird, bedeutet jedoch, dass das Element sowohl die Viewport-Größe als auch vollständig im Viewport sein muss, um true zu erhalten, was leicht zu falschen Negativen führt. Wenn Sie feststellen möchten, ob sich ein Element überhaupt im Ansichtsfenster befindet, ist ryanve's answer close, aber das getestete Element sollte das Ansichtsfenster überlappen. Versuchen Sie Folgendes:

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

Als öffentlicher Dienst:
Dans Antwort mit den korrekten Berechnungen (Element kann ein Fenster sein, insbesondere auf dem Bildschirm eines Mobiltelefons) und korrektes Testen von jQuery sowie das Hinzufügen von isElementPartiallyInViewport:

Übrigens: Der Unterschied zwischen difference zwischen window.innerWidth und document.documentElement.clientWidth ist, dass clientWidth/clientHeight die Bildlaufleiste nicht enthält, während window.innerWidth/Height dies tut.

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

Testfall

<!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>
30
Stefan Steiger

Es gibt ein jQuery-Plugin namens inview , das den Job ausführt

25

Siehe die Quelle von verge , die getBoundingClientRect verwendet. Es ist wie:

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

}

Gibt true zurück, wenn sich any Teil des Elements im Ansichtsfenster befindet.

24
ryanve

meine kürzere und schnellere Version.

function isElementOutViewport(el){
    var rect = el.getBoundingClientRect();
    return rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight;
}

fügen Sie bei Bedarf jsFiddle hinzu https://jsfiddle.net/on1g619L/1/

22
Eric Chen

Ich fand es beunruhigend, dass es keine jQuery zentrierte Version der Funktionalität gab. Als ich auf Dans Lösung stieß, erkundete ich die Gelegenheit, etwas für Leute anzubieten, die gerne im jQuery OO - Stil programmieren. Stellen Sie sicher, dass Sie einen Bildlauf nach oben durchführen und eine Bestätigung zu Dans Code hinterlassen. Es ist schön und bissig und wirkt für mich wie ein Zauber.

bada bing bada boom

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

Verwendungszweck

$(window).on('scroll',function(){ 

    if( $('footer').inView() ) {
        // do cool stuff
    }

});
19
r3wt

Ich finde, dass die akzeptierte Antwort für die meisten Anwendungsfälle zu kompliziert ist. Dieser Code erledigt die Arbeit gut (mit JQuery) und unterscheidet zwischen vollständig sichtbaren und teilweise sichtbaren Elementen. 

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");
    }
});
8
Adam Rehal

Alle Antworten, auf die ich hier gestoßen bin, überprüfen nur, ob das Element im aktuellen Ansichtsfenster positioniert ist. Aber das bedeutet nicht, dass es sichtbar ist.
Was ist, wenn sich das angegebene Element in einem div mit überfließendem Inhalt befindet und aus dem Blickfeld gerollt wird?

Um das zu lösen, müssen Sie prüfen, ob das Element in allen Eltern enthalten ist.
Meine Lösung macht genau das:

Sie können auch angeben, wie viel des Elements sichtbar sein muss.

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

Diese Lösung ignorierte die Tatsache, dass Elemente aufgrund anderer Fakten wie opacity: 0 möglicherweise nicht sichtbar sind. 

Ich habe diese Lösung in Chrome und Internet Explorer 11 getestet.

5
Domysee

Die neue Intersection Observer API geht diese Frage sehr direkt an.

Diese Lösung benötigt eine Polyfüllung, da Safari, Opera und IE dies noch nicht unterstützen. (Die Polyfüllung ist in der Lösung enthalten).

In dieser Lösung befindet sich eine Box außerhalb der Sicht, die das Ziel ist (beobachtet). Wenn es angezeigt wird, ist die Schaltfläche oben in der Kopfzeile ausgeblendet. Es wird angezeigt, sobald die Box die Ansicht verlässt.

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>
4
Randy Casburn

Ich denke, dass dies ein funktionaler Weg ist, dies zu tun. Die Antwort von Dan funktioniert nicht im rekursiven Kontext.

Diese Funktion löst das Problem, wenn sich Ihr Element in anderen scrollbaren divs befindet, indem Sie alle Ebenen rekursiv über dem HTML-Tag testen und im ersten false stoppen.

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

Basierend auf der oben genannten Lösung von @ dan ( https://stackoverflow.com/a/7557433/5628 ), hatte ich einen Versuch, die Implementierung aufzuräumen, sodass die mehrfache Verwendung auf derselben Seite einfacher ist:

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

});

Ich verwende es so, dass, wenn das Element in die Ansicht gerollt wird, eine Klasse hinzugefügt wird, die eine CSS-Keyframe-Animation auslöst. Es ist ziemlich unkompliziert und funktioniert besonders gut, wenn Sie mindestens 10 Dinge zum bedingten Animieren auf einer Seite haben.

Ich hoffe es hilft!

2
Pirijan

Kommt drauf an was du mit sichtbar meinst. Wenn Sie meinen, dass es derzeit auf der Seite angezeigt wird, können Sie die Position des Bildlaufs anhand der y-Versatzelemente und der aktuellen Bildlaufposition berechnen.

2
roryf

So einfach wie es geht IMO:

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

Die einfache und kleine Lösung, die für mich funktioniert hat.

Beispiel Sie möchten sehen, ob das Element in einem übergeordneten Element mit Überlaufbildlauf sichtbar ist.

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

Hier ist meine Lösung, es funktioniert, wenn ein Element in einem scrollbaren Container versteckt ist. 

Hier ist eine Demo (versuche die Fenstergröße zu ändern)

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

Ich musste nur überprüfen, ob es in der Y-Achse sichtbar ist (für ein Scrolling-Ajax-Load-Feature mit mehr Datensätzen). 

1
Ally

Ich hatte die gleiche Frage und habe es mit getBoundingClientRect () herausgefunden. Dieser Code ist vollständig 'generisch' und muss nur einmal geschrieben werden, damit er funktioniert (Sie müssen ihn nicht für jedes Element schreiben, von dem Sie wissen möchten, dass es sich im Ansichtsfenster befindet). Dieser Code prüft nur, ob er vertikal im Ansichtsfenster nicht horizontal liegt. In diesem Fall enthält die Variable (Array) 'elements' alle Elemente, die Sie im Ansichtsfenster als vertikal prüfen. Nehmen Sie also alle gewünschten Elemente und speichern Sie sie dort. Die for-Schleife durchläuft jedes Element und prüft, ob es vertikal im Ansichtsfenster ist. Dieser Code führt jedes Mal der Benutzer scrollt! Wenn das getBoudingClientRect (). Top weniger als 3/4 des Ansichtsfensters ist (das Element ist ein Viertel im Ansichtsfenster), wird es als 'im Ansichtsfenster' registriert. Da der Code generisch ist, sollten Sie wissen, welches Element sich im Viewport befindet. Um dies herauszufinden, können Sie es anhand von benutzerdefinierten Attributen, Knotennamen, IDs, Klassennamen usw. bestimmen. Hier ist mein Code (Sag mir, wenn es nicht funktioniert, wurde es getestet in IE 11, FireFox 40.0.3, Chrome Version 45.0.2454.85 m, Opera 31.0.1889.174 und Edge mit Windows 10, [ noch nicht 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.');
   }
};

Hoffe das hilft jemandem :-)

0
www139

Eine bessere Lösung:

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;    
}
0
rainyjune

Prüft, ob das Element mindestens teilweise sichtbar ist (vertikale Abmessung)

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

Einfachste Lösung als Kompatibilität von Element.getBoundingClientRect () ist perfekt geworden:

function inView(el) {
    let box = el.getBoundingClientRect();
    return box.top < window.innerHeight && box.bottom >= 0;
}
0
MiXT4PE

Hier ist eine Funktion, die anzeigt, ob ein Element im aktuellen Ansichtsfenster eines parent -Elementes sichtbar ist:

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