Frage

Gibt es eine effiziente Möglichkeit zu sagen, ob ein DOM-Element (in einem HTML-Dokument), die derzeit sichtbar ist (erscheint im Ansichtsfenstern )?

(Die Frage bezieht sich auf Firefox)

War es hilfreich?

Lösung

Update: Die Zeit schreitet voran und so unseren Browser hat. Diese Technik wird nicht mehr empfohlen und Sie sollten unter ( https://stackoverflow.com/ @ Dan-Lösung verwenden a / 7557433/5628 ), wenn Sie nicht brauchen, um Unterstützung IE <7.

Original-Lösung (jetzt veraltet):

Dies wird prüfen, ob das Element vollständig sichtbar im aktuellen Ansichtsfenster 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
  );
}

Andere Tipps

Jetzt den meisten Browsern Unterstützung getBoundingClientRect Methode, die die beste Praxis geworden ist. eine alte Antwort zu verwenden ist sehr langsam , nicht korrekt und hat einige Bugs .

Die Lösung die richtige ist, ausgewählt fast nie genau . Sie können href="http://javascript.ru/ui/offset" mehr um seine Fehler zu lesen.


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

Wie zu verwenden:

Sie können sicher sein, dass die Funktion über kehren richtige Antwort im Moment der Zeit gegeben, wenn es aufgerufen wird, aber was Element Sichtbarkeit als Ereignis über Tracking?

Setzen Sie den folgenden Code am unteren Rand des <body> Tag:

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 tun, können sie Ihr Element Sichtbarkeit natürlich ändern.

Richtlinien und allgemeine Probleme:

Vielleicht brauchen Sie Seite Zoom / mobile Gerät Prise verfolgen? jQuery sollte behandeln Zoom / kneifen Cross-Browser, sonst ersten oder second Link sollte Ihnen helfen.

Wenn Sie ändern DOM , kann es die Sichtbarkeit des Elements beeinflussen. Sie sollten manuell die Kontrolle über das und rufen handler() nehmen. Leider haben wir keinen Fall Cross-Browser-onrepaint. Auf der anderen Seite, die uns Optimierungen vornehmen können, und führen Sie erneut überprüfen nur auf DOM Änderungen, die Element Sichtbarkeit ändern kann.

Never Ever verwenden es in jQuery $ (document) .ready () nur, weil es keine Garantie CSS wurde in diesem Moment angewendet . Ihr Code kann auf der Festplatte lokal mit Ihrem CSS arbeiten, aber einmal auf Remote-Server setzt es fehl.

Nach DOMContentLoaded abgefeuert wird, Stile angewendet , aber the Bilder sind noch nicht geladen. So sollten wir window.onload Ereignis-Listener hinzufügen.

Wir können nicht zoomen / Prise Ereignis noch fangen.

Der letzte Ausweg könnte den folgenden Code sein:

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

Sie können die ehrfürchtige Funktion pageVisibiliy HTML5-API, wenn Sie sich interessieren, wenn die Registerkarte mit Ihrer Webseite aktiv und sichtbar.

TODO: diese Methode nicht behandelt zwei Situationen:

Update

In modernen Browsern, können Sie die Überschneidung Observer API die bietet die folgenden Vorteile:

  • Bessere Leistung als für Scroll-Ereignisse hören
  • Werke in Cross-Domain-iframes
  • Kann sagen, ob ein Element behindert / kreuzende andere

Kreuzung Observer ist auf dem Weg zu einem vollwertigen Standard zu sein und ist bereits in Chrome 51+, 15+ Rande und Firefox 55+ unterstützt und ist in der Entwicklung für Safari. Es gibt auch eine polyfill zur Verfügung.


Zurück Antwort

Es gibt einige Probleme mit der Antwort zur Verfügung gestellt von Dan das könnte es ein ungeeigneter Ansatz für einige Situationen machen. Einige dieser Fragen werden in seiner Antwort nahe der Unterseite weisen darauf hin, dass sein Code falsch positive Ergebnisse für Elemente geben, die sind:

  • Verborgen von einem anderen Element vor der einen getesteten
  • außerhalb des sichtbaren Bereichs eines Elternteils oder Vorfahre Element
  • Ein Element oder seine Kinder versteckt durch die CSS-Eigenschaft clip mit

Diese Einschränkungen in den folgenden Ergebnissen eines einfacher Test :

Failed-Test, mit isElementInViewport

Die Lösung: isElementVisible()

Hier ist eine Lösung für diese Probleme, mit dem Testergebnis unten und eine Erklärung von einigen Teilen 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))
    );
}
  

Passing-Test: http://jsfiddle.net/AndyE/cAY8c/

Und das Ergebnis:

Test bestanden, mit isElementVisible

Zusätzliche Hinweise

Diese Methode ist nicht ohne seine eigenen Grenzen, aber. Zum Beispiel kann ein Element mit einem niedrigen Z-Index als ein anderes Element an der gleichen Stelle getestet werden würde als verborgenes selbst identifiziert, wenn das Element vor verbirgt nicht tatsächlich einen Teil davon. Dennoch hat dieses Verfahren seine Verwendungen in einigen Fällen, dass Dan-Lösung nicht abgedeckt werden.

Sowohl element.getBoundingClientRect() und document.elementFromPoint() ist Teil der CSSOM Working Draft-Spezifikation und sind in mindestens IE 6 und höher und die meisten Desktop-Browser für eine lange Zeit (wenn auch nicht perfekt) unterstützt. Siehe Quirksmode auf diese Funktionen für weitere Informationen .

contains() wird verwendet, um festzustellen, ob das Element durch document.elementFromPoint() zurück ein Kindknoten des Elements wir für Sichtbarkeit zu testen. Es gibt auch dann, wenn das zurückgegebene Element das gleiche Element ist. Dies macht nur die Überprüfung robuster. Es ist in allen gängigen Browsern unterstützt, Firefox 9.0 die letzte von ihnen, um sie hinzuzufügen. Für ältere Firefox-Unterstützung, Geschichte dieser Antwort überprüfen.

Wenn Sie mehr Punkte zu testen um das Element für die Sichtbarkeit, dh um sicherzustellen, dass das Element nicht mehr als abgedeckt ist, sagen wir, 50% -es wäre nicht viel, um den letzten Teil der Antwort auf einstellen . Jedoch darüber im Klaren sein, dass es wahrscheinlich sehr langsam wäre, wenn Sie jedes Pixel, um sicherzustellen, überprüfen es zu 100% sichtbar war.

Ich habe versucht, Dan Antwort aber die Algebra verwendet, um die Grenzen zu bestimmen, bedeutet, dass das Element sowohl ≤ Ansichtsfenster Größe sein muss, und vollständig innerhalb des Ansichtsfenster zu bekommen true, leicht zu falschen Negativen führen. Wenn Sie möchten, um zu bestimmen, ob ein Element in der Ansicht überhaupt ist, ryanve Antwort ist in der Nähe, aber das Element getestet wird, sollte das Ansichtsfenster überlappt, so versuchen Sie dies:

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

Als öffentlicher Dienst:
Dan Antwort mit den richtigen Berechnungen (Element kann> Fenster, vor allem auf Handy-Displays) und korrekte jQuery-Tests, sowie das Hinzufügen isElementPartiallyInViewport:

By the way, die Differenz zwischen window.innerWidth und document.documentElement.clientWidth ist, dass client / client nicht die Scrollbar umfassen, während window.innerWidth / Höhe der Fall ist.

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>

Es ist jQuery-Plugin InView aufgerufen, macht den Job

Sehen Sie die Quelle der kurz davor , die verwendet getBoundingClientRect . 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 wenn jede Teil des Elements ist im Ansichtsfenster.

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

jsFiddle nach Bedarf hinzufügen https://jsfiddle.net/on1g619L/1/

Ich fand es beunruhigend, dass es keine jQuery centric Version der Funktionalität zur Verfügung stand. Als ich kam über Dans Lösung ausspioniert ich die Möglichkeit, etwas für Leute zu schaffen, die in der jQuery OO-Stil programmieren möchten. Achten Sie darauf, um nach oben und lassen einen upvote auf Dans Code. Es ist schön und bissig und wirkt wie ein Zauber für mich.

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

Verwendung

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

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

});

Ich finde, dass die akzeptierte Antwort hier zu kompliziert ist für die meisten Anwendungsfälle. Dieser Code macht den Job gut (mit JQuery) und unterscheidet zwischen vollständig sichtbar 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");
    }
});

Alle Antworten, die ich hier nur erlebt habe prüfen, ob das Element ist innerhalb des aktuellen Ansichtsfenster positioniert . Aber die bedeutet nicht, dass es sichtbar ist .
Was passiert, wenn das angegebene Element innerhalb eines div begnügt sich mit überfüllt, und es wird aus der Sicht gescrollt?

Um das zu lösen, würden Sie überprüfen, ob das Element von allen Eltern enthalten ist.
Meine Lösung tut genau das:

Es erlaubt Ihnen auch angeben, wie viel von dem Element 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 ignoriert die Tatsache, dass Elemente aufgrund anderer Tatsachen nicht sichtbar sein können, wie opacity: 0.

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

Der neue Überschneidung Observer API diese Frage befasst sich sehr direkt an.

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

Bei dieser Lösung gibt es ein Feld aus der Ansicht, dass das Ziel (beobachtet). Wenn es in den Blick kommt, ist die Schaltfläche oben im Header verborgen. Es wird gezeigt, sobald das Feld der Ansicht lä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>

Ich denke, dies ist eine funktionelle Art und Weise ist, es zu tun. Die Antwort des Dan nicht in rekursiven Kontext arbeiten.

lösen dieser Funktion wird das Problem, wenn Ihr Element in anderen scrollbaren divs ist durch alle Ebenen, um die HTML-Tag rekursiv oberen Testen und stoppt in der ersten falsch.

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

Basierend auf @ dan Lösung oben ( https://stackoverflow.com/a/7557433/5628 ), I eine go hatte bei Durchführung der Reinigung, so dass es mehrere Male auf der gleichen Seite mit einfacher:

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

});

So wie ich es bin ist, dass, wenn das Element blättert in Sicht, ich hinzufüge, eine Klasse, die eine CSS-Keyframe-Animation auslöst. Es ist ziemlich einfach und funktioniert besonders gut, wenn man wie 10+ Dinge hat bedingt auf einer Seite zu animieren.

Hoffe, es hilft!

Hier ist meine Lösung, wird es funktionieren, wenn ein Element in einem Scroll-able Containern versteckt ist.

Hier ist eine Demo (versuchen Sie, Sizing das Fenster)

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 brauche nur zu prüfen, ob es in der Y-Achse (für eine Rolle im Ajax-Last mehr Datensätze verfügen) sichtbar ist.

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

Beispiel: Sie wollen sehen, ob das Element in übergeordnetem Elemente sichtbar ist, der Überlauf scroll hat.

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

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

Prüft, ob Element zumindest teilweise in Ansicht (vertikale Dimension):

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

hatte ich die gleiche Frage und es herausgefunden von getBoundingClientRect () verwenden. Dieser Code ist vollständig ‚allgemeiner‘ und hat nur einmal geschrieben werden, damit es funktioniert (man es nicht schreiben für jedes Element muß, die Sie im Ansichtsfenster wissen wollen). Dieser Code überprüft nur, um zu sehen, ob sie vertikal in der Ansicht sind nicht horizontal . In diesem Fall hält die Variable (Array) ‚Elemente‘ alle Elemente, die Sie überprüfen in der Ansicht zu sein, vertikal, also alle Elemente greifen Sie überall wollen und speichern Sie sie dort. Das ‚for loop‘, Schleifen durch jedes Element und überprüft, ob er sich vertikal in dem Darstellungsfeld ist. Dieser Code ausgeführt jedes Mal scrollt der Benutzer! Wenn die getBoudingClientRect (). Top weniger als 3/4 der Darstellungsfeld (das Element ist ein Viertel in dem Darstellungsfeld), registriert sie als ‚im Ansichtsfenster‘. Da der Code generisch ist, wollen Sie wissen, ‚was‘ Element in der Ansicht ist. Um das herauszufinden, können Sie es durch benutzerdefinierte Attribut, Knotenname, ID, Klassennamen bestimmen und vieles mehr. Hier ist mein Code (Sag mir, wenn es nicht funktioniert, hat es in IE 11, FireFox 40.0.3, Chrome Version 45.0.2454.85 m, Opera 31.0.1889.174 und Edge-Windows 10, [nicht Safari noch] getestet ) ...

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

Hope, das hilft jemand: -)

Dies ist eine Funktion, wenn ein Element in sichtbar im aktuellen Ansichtsfenster eines Elternteil sagt Element:

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

Wie einfacher als es IMO bekommen:

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

Ich benutze diese Funktion (es prüft nur, wenn die y da die meiste Zeit InScreen wird die x ist nicht erforderlich)

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

}

Für eine ähnliche Herausforderung, die ich habe es wirklich genossen diesem Kern die scrollIntoViewIfNeeded () .

Alle notwendigen Kung Fu beantworten musste innerhalb dieses Blocks:

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 bezieht sich auf das Element, das Sie wissen wollen, ob es heißt overTop oder overBottom ist - nur die Drift bekommen sollte ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top