it-swarm-eu.dev

Come capire se un elemento DOM è visibile nella finestra corrente?

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

(La domanda riguarda Firefox)

807
benzaita

Aggiornamento: Il tempo passa e anche i nostri browser. Questa tecnica non è più raccomandata e dovresti usare la soluzione di @ Dan qui sotto ( https://stackoverflow.com/a/7557433/5628 ) se non hai bisogno di supportare IE <7.

Soluzione originale (ormai obsoleta):

Questo controllerà 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 modificare questo semplicemente per determinare se una qualsiasi parte dell'elemento è visibile nel viewport:

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

Ora gran parte dei browser support getBoundingClientRect method, che è diventata la migliore pratica. L'uso di una vecchia risposta è molto lento , non accurato e ha diversi bug .

La soluzione selezionata come corretta è quasi mai precisa . Puoi saperne di più sui 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 usare:

Puoi essere sicuro che la funzione sopra riportata restituisce la risposta corretta al momento del momento in cui viene chiamata, ma per quanto riguarda la visibilità dell'elemento di monitoraggio come evento?

Inserisci il seguente codice nella parte inferiore del tag <body>:

function onVisibilityChange(el, callback) {
    var old_visible;
    return function () {
        var visible = isElementInViewport(el);
        if (visible != old_visible) {
            old_visible = visible;
            if (typeof callback == 'function') {
                callback();
            }
        }
    }
}

var handler = onVisibilityChange(el, function() {
    /* your code go here */
});


//jQuery
$(window).on('DOMContentLoaded load resize scroll', handler); 

/* //non-jQuery
if (window.addEventListener) {
    addEventListener('DOMContentLoaded', handler, false); 
    addEventListener('load', handler, false); 
    addEventListener('scroll', handler, false); 
    addEventListener('resize', handler, false); 
} else if (window.attachEvent)  {
    attachEvent('onDOMContentLoaded', handler); // IE9+ :(
    attachEvent('onload', handler);
    attachEvent('onscroll', handler);
    attachEvent('onresize', handler);
}
*/

Se fai qualche modifica DOM, possono ovviamente cambiare la visibilità del tuo elemento.

Linee guida e problemi comuni:

Forse hai bisogno di monitorare lo zoom della pagina/il pizzico del dispositivo mobile? jQuery dovrebbe gestire zoom/pizzicare cross browser, altrimenti first or second link dovrebbe aiutarti. 

Se si modifica DOM, può influire sulla visibilità dell'elemento. Dovresti prenderne il controllo e chiamare handler() manualmente. Sfortunatamente, non abbiamo un evento onrepaint cross browser. D'altra parte ciò ci consente di fare ottimizzazioni ed eseguire un nuovo controllo solo sulle modifiche DOM che possono modificare la visibilità degli elementi.

Never Ever lo usa all'interno di jQuery $ (document) .ready () only, perché non esiste alcuna garanzia che il CSS sia stato applicato in questo momento. Il tuo codice può funzionare localmente con il tuo CSS sul disco rigido, ma una volta messo sul server remoto fallirà.

Dopo che DOMContentLoaded è stato attivato, gli stili sono applicati , ma le immagini non sono ancora state caricate . Quindi, dovremmo aggiungere window.onload listener di eventi.

Non possiamo ancora catturare l'evento zoom/pizzico.

L'ultima risorsa potrebbe essere il seguente codice:

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

Puoi utilizzare la funzione impressionante pageVisibiliy HTML5 API se ti interessa se la scheda con la tua pagina web è attiva e visibile.

TODO: questo metodo non gestisce due situazioni:

1258
Dan

Aggiornare

Nei browser moderni, potresti voler controllare l'API di Intersection Observer che offre i seguenti vantaggi:

  • Prestazioni migliori rispetto all'ascolto di eventi di scorrimento
  • Funziona in iframe cross domain
  • Può sapere se un elemento sta ostruendo/intersecando un altro

Intersection Observer è sulla buona strada per essere uno standard completo 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 basso, che il suo codice darà falsi positivi per elementi che sono:

  • Nascosto da un altro elemento di fronte a quello in prova
  • Al di fuori dell'area visibile di un elemento genitore 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 :

Failed test, using isElementInViewport

La soluzione: isElementVisible()

Ecco una soluzione a questi problemi, con il risultato del test seguente 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))
    );
}

Passing test:http://jsfiddle.net/AndyE/cAY8c/

E il risultato:

Passed test, using isElementVisible

Note aggiuntive

Questo metodo non è senza i suoi limiti, tuttavia. Ad esempio, un elemento testato con un indice z inferiore rispetto a un altro elemento nella stessa posizione verrà identificato come nascosto anche se l'elemento in primo piano non ne nasconde effettivamente alcuna parte. Tuttavia, questo metodo ha i suoi usi in alcuni casi che la soluzione di Dan non copre.

Sia element.getBoundingClientRect() che document.elementFromPoint() fanno parte delle specifiche CSS D Working del lavoro e sono supportati in almeno IE 6 e versioni successive e la maggior parte browser desktop per molto tempo (anche se non perfettamente). Vedi Quirksmode su queste funzioni per maggiori informazioni.

contains() è usato per vedere se l'elemento restituito da document.elementFromPoint() è un nodo figlio dell'elemento che stiamo testando per 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 di essi ad aggiungerlo. Per il supporto di Firefox precedente, controlla la cronologia di questa risposta.

Se vuoi testare più punti intorno all'elemento per la visibilità, ad esempio, per assicurarti che l'elemento non sia coperto da più di, ad esempio, il 50%, non ci vorrà molto per regolare l'ultima parte della risposta. Tuttavia, tieni presente che sarebbe probabilmente molto lento se hai controllato ogni pixel per assicurarti che fosse visibile al 100%.

143
Andy E

Ho provato La risposta di Dancomunque l'algebra usata per determinare i limiti significa che l'elemento deve essere ≤ la dimensione del viewport e completamente all'interno del viewport per ottenere true, portando facilmente a falsi negativi. Se vuoi determinare se un elemento è nella finestra, la risposta di ryanve è chiusa ma l'elemento da testare 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() */;
}
51
Walf

Come servizio pubblico:
La risposta di Dan con i calcoli corretti (l'elemento può essere> finestra, in particolare sugli schermi dei telefoni cellulari), correggere i test jQuery e aggiungere isElementPartiallyInViewport:

A proposito, la difference tra window.innerWidth e document.documentElement.clientWidth è che 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);
}

Test-caso

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

C'è un plugin jQuery chiamato inview che fa il lavoro

25

Vedi la fonte di verge , che usa 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 any parte dell'elemento si trova nella vista.

24
ryanve

la mia versione più corta e 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/

22
Eric Chen

Ho trovato preoccupante che non ci fosse una versione jQuery centric della funzionalità disponibile. Quando mi sono imbattuto la soluzione di Dan ho spiato l'opportunità di fornire qualcosa per persone che amano programmare nello stile jQuery OO. Assicurati di scorrere verso l'alto e lasciare un upvote 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();
});

usage

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

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

});
19
r3wt

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

Tutte le risposte che ho incontrato qui controllano solo se l'elemento è posizionato all'interno della finestra corrente . Ma quello non significa che sia visibile .
Cosa succede se l'elemento dato si trova all'interno di un div con contenuti che straripano e viene fatto scorrere fuori dalla vista?

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

Permette anche di specificare quanto deve essere visibile l'elemento.

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 provato questa soluzione in Chrome e Internet Explorer 11.

5
Domysee

La nuova Intersection Observer API affronta questa domanda molto direttamente.

Questa soluzione richiede un polyfill come Safari, Opera e IE non supportano ancora questo. (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 mostrato quando la finestra 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>
4
Randy Casburn

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

Questa funzione risolve il problema quando il tuo elemento si trova all'interno di altri div affiancabili testando qualsiasi livello in modo ricorsivo superiore 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)
    );
};
3
ton

Sulla base della soluzione di @ dan sopra ( https://stackoverflow.com/a/7557433/5628 ), ho provato a ripulire l'implementazione in modo tale che utilizzarla più volte sulla 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!

2
Pirijan

Dipende da cosa intendi per visibile. Se si intende che è attualmente mostrato nella pagina, data la posizione di scorrimento, è possibile calcolarlo in base agli elementi y offset e alla posizione corrente di scorrimento.

2
roryf

Più semplice come può ottenere IMO:

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

La soluzione facile e piccola che ha funzionato per me.

Esempio Si desidera vedere se l'elemento è visibile nell'elemento padre che ha scroll 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');
     }
})
1
Stevan Tosic

Ecco la mia soluzione, funzionerà se un elemento è nascosto all'interno di un contenitore scroll-able. 

Ecco una demo (prova a ridimensionare la finestra)

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 sull'asse Y (per una carica ajax scorrevole più funzionalità di registrazione). 

1
Ally

Ho avuto la stessa domanda e l'ho capito usando getBoundingClientRect (). Questo codice è completamente "generico" e deve essere scritto una volta sola affinché funzioni (non è necessario scriverlo per ogni elemento che si desidera conoscere nella vista). Questo codice controlla solo se è verticalmente nel viewport non orizzontalmente . In questo caso, la variabile (array) 'elements' contiene tutti gli elementi che stai controllando per essere verticalmente nella finestra, quindi prendi tutti gli elementi che vuoi ovunque e memorizzali lì. Il ciclo "for", scorre attraverso ciascun elemento e controlla se è verticalmente nella finestra. Questo codice esegue ogni volta l'utente scorre! Se getBoudingClientRect (). Top è inferiore a 3/4 della finestra (l'elemento è un quarto nella finestra), viene registrato come "nella vista". Dal momento che il codice è generico, ti consigliamo di sapere "quale" elemento si trova nella vista. Per scoprirlo, è possibile determinarlo per attributo personalizzato, nome nodo, id, nome classe e altro. Ecco il mio codice (dimmi se non funziona, è stato testato in IE 11, FireFox 40.0.3, Chrome versione 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 :-)

0
www139

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

Controlla se l'elemento è almeno parzialmente in vista (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} 
}
0
Lumic

Ecco una funzione che indica se un elemento è visibile nella finestra corrente di un elemento parent:

function inParentViewport(el, pa) {
    if (typeof jQuery === "function"){
        if (el instanceof jQuery)
            el = el[0];
        if (pa instanceof jQuery)
            pa = pa[0];
    }

    var e = el.getBoundingClientRect();
    var p = pa.getBoundingClientRect();

    return (
        e.bottom >= p.top &&
        e.right >= p.left &&
        e.top <= p.bottom &&
        e.left <= p.right
    );
}
0
ssten