Domanda

C'è un modo efficace per capire se un elemento del DOM (in un documento HTML) è attualmente visibile (appare nel viewport)?

(La domanda si riferisce a Firefox)

È stato utile?

Soluzione

Aggiornamento: il tempo avanza e così anche i nostri browser. Questa tecnica non è più consigliata e dovresti utilizzare la soluzione di @ Dan di seguito ( https://stackoverflow.com/ a / 7557433/5628 ) se non è necessario supportare IE < 7.

Soluzione originale (ora obsoleta):

Questo verificherà se l'elemento è interamente visibile nella finestra corrente:

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

È possibile modificarlo semplicemente per determinare se una parte dell'elemento è visibile nella finestra:

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

Altri suggerimenti

Ora la maggior parte dei browser supporto getBoundingClientRect il metodo, che è diventata la migliore pratica.Utilizzando una vecchia risposta è molto lento, non accurate e ha diversi bug.

La soluzione scelta corretta è quasi mai preciso.È possibile leggi di più circa i suoi bug.


Questa soluzione è stata testata su IE7+, iOS5+ Safari, Android2+, Blackberry, Opera Mobile, e 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() */
    );
}

Come utilizzare:

Si può essere sicuri che la funzione di cui sopra restituisce risposta corretta al momento di tempo in cui è chiamato, ma che cosa circa il monitoraggio la visibilità dell'elemento come un evento?

Inserire il seguente codice nella parte inferiore del vostro <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);
}
*/

Se fate qualunque DOM modifiche, possono cambiare la visibilità dell'elemento di corso.

Linee guida e i trabocchetti:

Forse avete bisogno di tenere traccia zoom della pagina / dispositivo mobile pizzico? jQuery deve gestire zoom/pinch cross browser, altrimenti prima o secondo link dovrebbe aiutare.

Se si modificare DOM, può interessare l'elemento di visibilità.Si dovrebbe prendere il controllo della che e chiamata handler() manualmente.Purtroppo, non abbiamo cross browser onrepaint evento.D'altra parte, che ci permette di fare ottimizzazioni ed eseguire nuovamente il check solo su DOM modifiche che possono cambiare la visibilità dell'elemento.

Mai E Poi Mai utilizzare all'interno di jQuery $(document).ready() solo, perché non c'è nessuna garanzia CSS è stato applicato in questo momento.Il codice è in grado di lavorare a livello locale con il CSS sul disco rigido, ma una volta messo sul server remoto avrà esito negativo.

Dopo DOMContentLoaded licenziato, gli stili vengono applicati, ma le immagini non sono state ancora caricate.Quindi, dovremmo aggiungere window.onload listener di eventi.

Non siamo in grado di prendere, zoom pizzico di eventi di sicurezza.

L'ultima spiaggia potrebbe essere il seguente codice:

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

È possibile utilizzare caratteristica impressionante pageVisibiliy API di HTML5 se ti interessa se la scheda con la pagina web è attivo e visibile.

TODO:questo metodo non consente di gestire due situazioni:

Aggiornamento

Nei browser moderni, potresti voler controllare API osservatore intersezione che offre i seguenti vantaggi:

  • Prestazioni migliori rispetto all'ascolto di eventi scroll
  • Funziona con iframe tra domini
  • Può dire se un elemento sta ostruendo / intersecando un altro

Intersection Observer sta per diventare uno standard a pieno titolo ed è già supportato in Chrome 51+, Edge 15+ e Firefox 55+ ed è in fase di sviluppo per Safari. C'è anche un polyfill disponibile.


Risposta precedente

Ci sono alcuni problemi con la risposta fornita da Dan che potrebbe renderlo un approccio inadatto per alcune situazioni. Alcuni di questi problemi sono indicati nella sua risposta in fondo, che il suo codice darà falsi positivi per elementi che sono:

  • Nascosto da un altro elemento di fronte a quello in fase di test
  • Al di fuori dell'area visibile di un elemento padre o antenato
  • Un elemento o i suoi figli nascosti utilizzando la proprietà CSS clip

Queste limitazioni sono dimostrate nei seguenti risultati di un test semplice :

Test fallito, usando isElementInViewport

La soluzione: isElementVisible()

Ecco una soluzione a questi problemi, con il risultato del test di seguito e una spiegazione di alcune parti del codice.

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

Test di superamento: http://jsfiddle.net/AndyE/cAY8c/

E il risultato:

Test superato, usando isElementVisible

Note aggiuntive

Questo metodo non è tuttavia privo di limiti. Ad esempio, un elemento in fase di test con un indice z inferiore rispetto a un altro elemento nella stessa posizione verrebbe identificato come nascosto anche se l'elemento di fronte non nasconde effettivamente alcuna parte di esso. Tuttavia, questo metodo ha i suoi usi in alcuni casi che la soluzione di Dan non copre.

Entrambi element.getBoundingClientRect() e document.elementFromPoint() fanno parte della specifica CSSOM Working Draft e sono supportati da almeno IE 6 e versioni successive e maggior parte dei browser desktop per lungo tempo (anche se non perfettamente) . Vedi Modalità Quirks su queste funzioni per ulteriori informazioni.

contains() viene utilizzato per vedere se l'elemento restituito da <=> è un nodo figlio dell'elemento che stiamo testando per la visibilità. Restituisce anche true se l'elemento restituito è lo stesso elemento. Questo rende il controllo più robusto. È supportato in tutti i principali browser, Firefox 9.0 è l'ultimo ad aggiungerlo. Per il supporto di Firefox precedente, controlla la cronologia di questa risposta.

Se si desidera testare più punti intorno all'elemento per la visibilità & # 8213; ovvero, per assicurarsi che l'elemento non sia coperto da più, per esempio, del 50% & # 8213; non lo farebbe impiega molto per regolare l'ultima parte della risposta. Tuttavia, tieni presente che probabilmente sarebbe molto lento se controllassi ogni pixel per assicurarti che fosse visibile al 100%.

Ho provato la risposta di Dan tuttavia l'algebra utilizzata per determinare i limiti significa che l'elemento deve essere entrambi & # 8804; la dimensione della finestra e completamente all'interno della finestra per ottenere true, portando facilmente a falsi negativi. Se vuoi determinare se un elemento è presente nel viewport, la risposta di ryanve è vicina ma l'elemento in fase di test dovrebbe sovrapporsi al viewport, quindi prova questo:

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

Come servizio pubblico:
La risposta di Dan con i calcoli corretti (l'elemento può essere & Gt; finestra, specialmente sugli schermi dei telefoni cellulari) e il corretto test jQuery, oltre ad aggiungere isElementPartiallyInViewport:

A proposito, la differenza tra window.innerWidth e document.documentElement.clientWidth è quel clientWidth / clientHeight non include la barra di scorrimento, mentre window.innerWidth / Height fa.

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

Prova e minuscole

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

Esiste un plug-in jQuery chiamato inview che fa il lavoro

Vedi l'origine di verge , che utilizza getBoundingClientRect . È come:

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

}

Restituisce true se qualsiasi parte dell'elemento è nella finestra.

la mia versione più corta e più veloce.

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

aggiungi jsFiddle come richiesto https://jsfiddle.net/on1g619L/1/

Ho trovato preoccupante che non esistesse una jQuery versione centrica della funzionalità disponibile. Quando mi sono imbattuto in la soluzione di Dan ho spiato l'opportunità di fornire qualcosa per le persone a cui piace programmare nello stile <=> OO . Assicurati di scorrere verso l'alto e lasciare un voto sul codice di Dan. È bello e scattante e funziona come un fascino per me.

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

Utilizzo

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

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

});

Trovo che la risposta accettata qui sia eccessivamente complicata per la maggior parte dei casi d'uso. Questo codice fa bene il lavoro (usando JQuery) e differenzia tra elementi completamente visibili e parzialmente visibili.

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

Tutte le risposte che ho incontrato qui verificano solo se l'elemento è posizionato all'interno della finestra corrente . Ma questo non significa che sia visibile .
Che cosa succede se un determinato elemento si trova all'interno di un div con contenuti straripanti e viene fatto scorrere fuori dalla vista?

Per risolverlo, dovresti controllare se l'elemento è contenuto da tutti i genitori.
La mia soluzione fa esattamente questo:

Ti consente anche di specificare la quantità di elemento che deve essere visibile.

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

Questa soluzione ha ignorato il fatto che gli elementi potrebbero non essere visibili a causa di altri fatti, come opacity: 0.

Ho testato questa soluzione in Chrome e Internet Explorer 11.

La nuova API di Intersection Observer affronta molto questa domanda direttamente.

Questa soluzione avrà bisogno di un polyfill poiché Safari, Opera e IE non lo supportano ancora. (il polyfill è incluso nella soluzione).

In questa soluzione, c'è un riquadro fuori dalla vista che è il bersaglio (osservato). Quando viene visualizzato, il pulsante nella parte superiore dell'intestazione è nascosto. Viene visualizzato quando la casella lascia la vista.

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>

Penso che questo sia un modo più funzionale per farlo. La risposta del Dan non funziona in un contesto ricorsivo.

Questa funzione risolve il problema quando il tuo elemento si trova all'interno di altri div scorrevoli testando tutti i livelli ricorsivamente superiori al tag HTML e si ferma nel primo falso.

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

Basato sulla soluzione di @ dan sopra ( https://stackoverflow.com/a/7557433/5628 ), I ho provato a ripulire l'implementazione in modo che utilizzarlo più volte nella stessa pagina sia più semplice:

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

});

Il modo in cui lo sto usando è che quando l'elemento scorre in vista, sto aggiungendo una classe che attiva un'animazione keyframe css. È piuttosto semplice e funziona particolarmente bene quando hai più di 10 cose da animare condizionatamente su una pagina.

Spero che sia d'aiuto!

Ecco la mia soluzione, funzionerà se un elemento è nascosto in un contenitore con scorrimento.

Ecco una demo (prova a ridimensionare la finestra in)

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

Avevo solo bisogno di verificare se è visibile nell'asse Y (per uno scorrimento ajax carica più record).

La soluzione semplice e piccola che ha funzionato per me.

Esempio Vuoi vedere se l'elemento è visibile nell'elemento genitore con scorrimento di overflow.

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

Una soluzione migliore:

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

Verifica se l'elemento è almeno parzialmente visibile (dimensione verticale):

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

Ho avuto la stessa domanda e l'ho capito usando getBoundingClientRect (). Questo codice è completamente "generico" e deve essere scritto solo una volta perché funzioni (non è necessario scriverlo per ogni elemento che si desidera sapere sia nel viewport). Questo codice controlla solo se è verticale nella finestra non orizzontale . In questo caso, gli 'elementi' variabili (array) contengono tutti gli elementi che stai controllando per essere posizionati verticalmente nella finestra, quindi prendi tutti gli elementi che vuoi ovunque e li memorizza lì. Il 'ciclo for', scorre attraverso ogni elemento e controlla se è verticale nella finestra. Questo codice esegue ogni volta l'utente scorre! Se getBoudingClientRect (). Top è inferiore a 3/4 del riquadro di visualizzazione (l'elemento è un quarto nel riquadro di visualizzazione), viene registrato come "nel riquadro di visualizzazione". Poiché il codice è generico, vorrai sapere quale "elemento" è presente nella finestra. Per scoprirlo, puoi determinarlo in base all'attributo personalizzato, al nome nodo, all'ID, al nome della classe e altro. Ecco il mio codice (dimmi se non funziona, è stato testato in IE 11, FireFox 40.0.3, versione Chrome 45.0.2454.85 m, Opera 31.0.1889.174 e Edge con Windows 10, [non ancora 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.');
   }
};

Spero che questo aiuti qualcuno :-)

Ecco una funzione che dice se un elemento è visibile nella vista corrente di un elemento principale :

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

Più semplice che può ottenere IMO:

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

Uso questa funzione (controlla solo se y è sullo schermo poiché la maggior parte delle volte non è necessaria)

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

}

Per una sfida simile mi sono davvero divertito questa sintesi che espone un polyfill per scrollIntoViewIfNeeded () .

Tutto il Kung Fu necessario per rispondere è all'interno di questo blocco:

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 si riferisce all'elemento che vuoi sapere se è cioè overTop o overBottom - dovresti solo ottenere la deriva ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top