Come verificare se l'elemento è visibile dopo lo scorrimento?


1170

Sto caricando elementi tramite AJAX. Alcuni di essi sono visibili solo se si scorre la pagina verso il basso.
Esiste un modo per sapere se un elemento si trova ora nella parte visibile della pagina?


42
vuol dire che vuole un metodo per sapere se un determinato elemento viene visualizzato nella finestra del browser o se l'utente deve scorrere per vederlo.
Romain Linsolas,

1
Per verificare se un elemento è completamente visibile in un contenitore, basta aggiungere un parametro selettore aggiuntivo e riutilizzare il codice elem per esso. Library.IsElementVisibleInContainer = function (elementSelector, containerSelector) { var containerViewTop = $(containerSelector).offset().top; var containerViewBottom = containerViewTop + $(containerSelector).height();
Lifes,



1
Tutte le risposte attiveranno il reflow in modo che possa essere il collo di bottiglia, si urla usare IntersectionObserver se supportato. Avrà prestazioni migliori sui browser moderni,
jcubic il

Risposte:


1258

Questo dovrebbe fare il trucco:

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

Funzione di utilità semplice Ciò consente di chiamare una funzione di utilità che accetta l'elemento che si sta cercando e se si desidera che l'elemento sia completamente visibile o parzialmente.

function Utils() {

}

Utils.prototype = {
    constructor: Utils,
    isElementInView: function (element, fullyInView) {
        var pageTop = $(window).scrollTop();
        var pageBottom = pageTop + $(window).height();
        var elementTop = $(element).offset().top;
        var elementBottom = elementTop + $(element).height();

        if (fullyInView === true) {
            return ((pageTop < elementTop) && (pageBottom > elementBottom));
        } else {
            return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
        }
    }
};

var Utils = new Utils();

uso

var isElementInView = Utils.isElementInView($('#flyout-left-container'), false);

if (isElementInView) {
    console.log('in view');
} else {
    console.log('out of view');
}

52
Nota che questo funziona solo se il documento è l'elemento da scorrere, cioè non stai controllando la visibilità di alcuni elementi all'interno di un riquadro interno scorrevole.
Andrew B.,

8
come aggiungere un piccolo offset?
Jürgen Paul,

5
Ha funzionato solo quando l'ho usato window.innerHeightinvece
Christian Schnorr il

2
Per elemTopho usato $(elem).position().tope per elemBottomho usato elemTop + $(elem).outerHeight(true).
Sarah Vessels,

13
Per: "Qualsiasi parte dell'elemento in vista", ho usato: ((((elemTop> = docViewTop) && (elemTop <= docViewBottom)) || ((elemBottom> = docViewTop) && (elemBottom <= docViewBottom)))
Grizly,

415

Questa risposta in vaniglia:

function isScrolledIntoView(el) {
    var rect = el.getBoundingClientRect();
    var elemTop = rect.top;
    var elemBottom = rect.bottom;

    // Only completely visible elements return true:
    var isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
    // Partially visible elements return true:
    //isVisible = elemTop < window.innerHeight && elemBottom >= 0;
    return isVisible;
}

27
non dovrebbe essere isVisible = elementTop < window.innerHeight && elementBottom >= 0? Altrimenti un elemento mezzo sullo schermo restituisce false.
Gman,

7
no. controllo se qualche elemento è completamente visibile sulla pagina. se desideri verificare la visibilità di alcune parti, puoi personalizzare questo frammento.
bravedick,

15
Trovo che questa risposta funzioni meglio della risposta scelta. Anche più semplice.
Adam Venezia,

12
Rispetto alla risposta approvata, questo funziona molto meglio con centinaia di elementi.
ncla,

5
vedere un piccolo violino che dimostra qui - jsfiddle.net/shaaraddalvi/4rp09jL0
upInCloud

122

Aggiornamento: usa IntersectionObserver


Il metodo migliore che ho trovato finora è il plugin di visualizzazione jQuery . Funziona come un fascino.

Imita un evento "compare" personalizzato, che si attiva quando un elemento scorre in vista o diventa altrimenti visibile all'utente.

$('#foo').appear(function() {
  $(this).text('Hello world');
});

Questo plug-in può essere utilizzato per prevenire richieste non necessarie di contenuto nascosto o al di fuori dell'area visualizzabile.


30
Questo è un plugin interessante, senza dubbio, ma non risponde alla domanda.
Jon Adams,

5
Mentre il plug-in jQuery è buono per i contenuti nell'area della pagina principale, sfortunatamente ha problemi con div di scorrimento a dimensione fissa con overflow. L'evento può attivarsi prematuramente quando l'elemento associato si trova all'interno dell'area visualizzabile della pagina ma al di fuori dell'area visualizzabile del div e quindi non si attiva come previsto quando l'elemento viene visualizzato nel div.
Peter,

17
C'è un plugin scomparire?
Shamoon,

3
@Shamoon controlla la fonte per il appear plugine probabilmente dovrai solo aggiungere un !posto per ottenere un disappearplugin.
Lucky Soni

5
Come nota, questo non funziona con jQuery 1.11.X github.com/morr/jquery.appear/issues/37
Jason Parham

86

Ecco la mia pura soluzione JavaScript che funziona se è nascosta anche all'interno di un contenitore scorrevole.

Demo qui (prova a ridimensionare anche la finestra)

var visibleY = function(el){
  var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height, 
    el = el.parentNode
  // Check if bottom of the element is off the page
  if (rect.bottom < 0) return false
  // Check its within the document viewport
  if (top > document.documentElement.clientHeight) return false
  do {
    rect = el.getBoundingClientRect()
    if (top <= rect.bottom === false) return false
    // Check if the element is out of view due to a container scrolling
    if ((top + height) <= rect.top) return false
    el = el.parentNode
  } while (el != document.body)
  return true
};

EDIT 2016-03-26: Ho aggiornato la soluzione per tenere conto dello scorrimento oltre l'elemento in modo che sia nascosto sopra la parte superiore del contenitore che può scorrere. MODIFICA 08-10-2018: aggiornato per essere gestito quando non viene visualizzato sopra lo schermo.


grazie, forse è meglio return top <= document.documentElement.clientHeight && top >= 0;
Yousef Salimpour,

16
+1 Questa è stata l'unica risposta codificata (cioè non di terze parti) che tiene conto della natura ricorsiva degli elementi. Ho ampliato per gestire lo scorrimento orizzontale, verticale e della pagina: jsfiddle.net/9nuqpgqa
Pebbl,

3
Questa soluzione controlla solo la parte superiore dell'elemento. Se il primo pixel superiore è visibile, tornerà vero anche se il resto dell'articolo non è visibile. Per verificare se l'intero elemento è visibile, è necessario controllare anche la proprietà inferiore.
Wojciech Jakubas,

2
Sì, pulito! Usato per aiutare a scrivere questa risposta (con credito come commento js).
Roamer-1888,

Mancante; dopo il secondo "return false" nel loop
Mikhail Ramendik,

46

Utilizzo dell'API IntersectionObserver (nativa nei browser moderni)

È facile ed efficiente determinare se un elemento è visibile nel viewpor, o in qualsiasi contenitore scorrevole, usando un osservatore .

scrollViene eliminata la necessità di allegare un evento e di controllare manualmente il callback dell'evento, quindi l'efficienza:

// this is the target which is observed
var target = document.querySelector('div');

// configure the intersection observer instance
var intersectionObserverOptions = {
  root: null,
  rootMargin: '150px',
  threshold: 1.0
}
    
var observer = new IntersectionObserver(onIntersection, intersectionObserverOptions);

// provide the observer with a target
observer.observe(target);

function onIntersection(entries){
  entries.forEach(entry => {
    console.clear();
    console.log(entry.intersectionRatio)
    target.classList.toggle('visible', entry.intersectionRatio > 0);
    
    // Are we in viewport?
    if (entry.intersectionRatio > 0) {
      // Stop watching 
      // observer.unobserve(entry.target);
    }
  });
}
.box{ width:100px; height:100px; background:red; margin:1000px; }
.box.visible{ background:green; }
Scroll both Vertically & Horizontally...
<div class='box'></div>


Visualizza la tabella di supporto dei browser (non supportata in IE / Safari)


4
Grazie! Questo funziona per me e anche farlo funzionare in IE11 con github.com/w3c/IntersectionObserver
Matt Wilson

Di gran lunga la migliore soluzione. Ha funzionato in IE11 senza polyfill!
Fabian von Ellerts,

Sfortunatamente, questo STILL non è supportato in Safari iOS / macOS. Assicurati di controllare i problemi perf se scegli di effettuare il polyfill, questo è un grande gruppo di utenti
Leland,

@Leland - dipende dal progetto. per tutti i miei progetti questo è un gruppo di 0 utenti assoluti. Non costruisco siti web ma un sistema web;)
vsync,

Sto cercando di eseguire questo in un ciclo su diversi elementi, ma non funziona. Qualche idea? Sto aggiungendo l'elemento al target in quel loop.
Sascha Grindau,

42

Il plugin jQuery Waypoints è molto bello qui.

$('.entry').waypoint(function() {
   alert('You have scrolled to an entry.');
});

Ci sono alcuni esempi sul sito del plugin .


3
Per me ha funzionato solo con un offset $('#my-div').waypoint(function() { console.log('Hello there!'); }, { offset: '100%' });
leymannx

21

Che ne dite di

function isInView(elem){
   return $(elem).offset().top - $(window).scrollTop() < $(elem).height() ;
}

Dopodiché puoi attivare ciò che vuoi una volta che l'elemento è visualizzato in questo modo

$(window).scroll(function(){
   if (isInView($('.classOfDivToCheck')))
      //fire whatever you what 
      dothis();
})

Per me funziona bene


1
Questo funziona per me, ma ho usato il, apparentemente più completa, la funzione isScrolledIntoView a stackoverflow.com/questions/487073/... :)
Meetai.com

3
Penso che dovrebbe essere $ (window) .scrollTop () <$ (elem) .offset (). Top + $ (elem) .height ();
Giovane

La mia modifica sarebbe così: `return $ (window) .scrollTop () + $ (window) .height ()> $ (elem) .offset (). Top + $ (elem) .height (); `
bubencode

15

WebResourcesDepot ha scritto uno script da caricare durante lo scorrimento che utilizza jQuery qualche tempo fa. Puoi vedere la loro demo live qui . Il punto forte della loro funzionalità era questo:

$(window).scroll(function(){
  if  ($(window).scrollTop() == $(document).height() - $(window).height()){
    lastAddedLiveFunc();
  }
});

function lastAddedLiveFunc() { 
  $('div#lastPostsLoader').html('<img src="images/bigLoader.gif">');
  $.post("default.asp?action=getLastPosts&lastPostID="+$(".wrdLatest:last").attr("id"),
    function(data){
        if (data != "") {
          $(".wrdLatest:last").after(data);         
        }
      $('div#lastPostsLoader').empty();
    });
};

15

Tweeked La fantastica funzione di Scott Dowding per le mie esigenze: viene utilizzata per scoprire se l'elemento è appena passato nello schermo, ovvero il bordo superiore.

function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}

12

Semplice vaniglia per verificare se element ( el) è visibile in div ( holder) scorrevole

function isElementVisible (el, holder) {
  holder = holder || document.body
  const { top, bottom, height } = el.getBoundingClientRect()
  const holderRect = holder.getBoundingClientRect()

  return top <= holderRect.top
    ? holderRect.top - top <= height
    : bottom - holderRect.bottom <= height
},

Utilizzo con jQuery:

var el = $('tr:last').get(0);
var holder = $('table').get(0);
isVisible =  isScrolledIntoView(el, holder);

2
In questa era delle applicazioni a pagina singola è diventato più comune verificare se un elemento è visibile all'interno di un altro elemento oltre alla finestra . Ecco perché questo ottiene il mio voto.
H Dog,

8

isScrolledIntoView è una funzione molto necessaria, quindi l'ho provato, funziona per elementi non più alti del viewport, ma se l'elemento è più grande del viewport non funziona. Per risolvere questo problema, modificare facilmente la condizione

return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));

a questo:

return (docViewBottom >= elemTop && docViewTop <= elemBottom);

Guarda la demo qui: http://jsfiddle.net/RRSmQ/


8

La maggior parte delle risposte qui non tiene conto del fatto che un elemento può anche essere nascosto perché è fatto scorrere fuori dalla vista di un div, non solo dell'intera pagina.

Per coprire questa possibilità, in pratica devi controllare se l'elemento è posizionato all'interno dei limiti di ciascuno dei suoi genitori.

Questa soluzione fa esattamente questo:

function(element, 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 = element.getBoundingClientRect();
    var parentRects = [];

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

Inoltre, consente di specificare in quale percentuale deve essere visibile in ciascuna direzione.
Non copre la possibilità che possa essere nascosto a causa di altri fattori, come display: hidden.

Questo dovrebbe funzionare in tutti i principali browser, poiché utilizza solo getBoundingClientRect. L'ho testato personalmente in Chrome e Internet Explorer 11.


Grazie per questo codice Mi chiedo come aggiungeresti il ​​listener di eventi su scroll in questo caso che hai più elementi scorrevoli nidificati? Sembra che l'aggiunta dell'ascoltatore alla sola finestra non sia sufficiente, dobbiamo tornare al genitore principale per aggiungere l'ascoltatore a ciascun contenitore scorrevole?
Mr1031011,

@ mr1031011 Dovrebbe essere possibile aggiungere il gestore alla finestra e quindi verificare la destinazione per identificare il contenitore che è stato fatto scorrere.
Domysee,

giusto, non funziona con l'esempio dato da @vanowm,
mr1031011

7
function isScrolledIntoView(elem) {
    var docViewTop = $(window).scrollTop(),
        docViewBottom = docViewTop + $(window).height(),
        elemTop = $(elem).offset().top,
     elemBottom = elemTop + $(elem).height();
   //Is more than half of the element visible
   return ((elemTop + ((elemBottom - elemTop)/2)) >= docViewTop && ((elemTop + ((elemBottom - elemTop)/2)) <= docViewBottom));
}

7

Ecco un'altra soluzione da http://web-profile.com.ua/

<script type="text/javascript">
$.fn.is_on_screen = function(){
    var win = $(window);
    var viewport = {
        top : win.scrollTop(),
        left : win.scrollLeft()
    };
    viewport.right = viewport.left + win.width();
    viewport.bottom = viewport.top + win.height();

    var bounds = this.offset();
    bounds.right = bounds.left + this.outerWidth();
    bounds.bottom = bounds.top + this.outerHeight();

    return (!(viewport.right < bounds.left || viewport.left > bounds.right ||    viewport.bottom < bounds.top || viewport.top > bounds.bottom));
 };

if( $('.target').length > 0 ) { // if target element exists in DOM
    if( $('.target').is_on_screen() ) { // if target element is visible on screen after DOM loaded
        $('.log').html('<div class="alert alert-success">target element is visible on screen</div>'); // log info       
    } else {
        $('.log').html('<div class="alert">target element is not visible on screen</div>'); // log info
    }
}
$(window).scroll(function(){ // bind window scroll event
if( $('.target').length > 0 ) { // if target element exists in DOM
    if( $('.target').is_on_screen() ) { // if target element is visible on screen after DOM loaded
        $('.log').html('<div class="alert alert-success">target element is visible on screen</div>'); // log info
    } else {
        $('.log').html('<div class="alert">target element is not visible on screen</div>'); // log info
    }
}
});
</script>

Guardalo in JSFiddle


7

Questo considera qualsiasi imbottitura, bordo o margine dell'elemento e elementi più grandi della finestra stessa.

function inViewport($ele) {
    var lBound = $(window).scrollTop(),
        uBound = lBound + $(window).height(),
        top = $ele.offset().top,
        bottom = top + $ele.outerHeight(true);

    return (top > lBound && top < uBound)
        || (bottom > lBound && bottom < uBound)
        || (lBound >= top && lBound <= bottom)
        || (uBound >= top && uBound <= bottom);
}

Per chiamarlo usa qualcosa del genere:

var $myElement = $('#my-element'),
    canUserSeeIt = inViewport($myElement);

console.log(canUserSeeIt); // true, if element is visible; false otherwise

7

Esiste un plug-in per jQuery chiamato inview che aggiunge un nuovo evento "inview".


Ecco un po 'di codice per un plugin jQuery che non utilizza eventi:

$.extend($.expr[':'],{
    inView: function(a) {
        var st = (document.documentElement.scrollTop || document.body.scrollTop),
            ot = $(a).offset().top,
            wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();
        return ot > st && ($(a).height() + ot) < (st + wh);
    }
});

(function( $ ) {
    $.fn.inView = function() {
        var st = (document.documentElement.scrollTop || document.body.scrollTop),
        ot = $(this).offset().top,
        wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();

        return ot > st && ($(this).height() + ot) < (st + wh);
    };
})( jQuery );

L'ho trovato in un commento qui ( http://remysharp.com/2009/01/26/element-in-view-event-plugin/ ) di un tipo chiamato James


Purtroppo, jQuery inview non è più gestito e non funziona con le versioni correnti di jQuery.
mikemaccana,

1
JQuery 1 è per il supporto del browser legacy, le nuove funzionalità sono in jQuery 2.
mikemaccana,

Il collegamento non mostra l'esempio poiché la pagina è stata aggiornata.
Professore di programmazione il

6

Avevo bisogno di controllare la visibilità negli elementi all'interno del contenitore DIV scorrevole

    //p = DIV container scrollable
    //e = element
    function visible_in_container(p, e) {
        var z = p.getBoundingClientRect();
        var r = e.getBoundingClientRect();

        // Check style visiblilty and off-limits
        return e.style.opacity > 0 && e.style.display !== 'none' &&
               e.style.visibility !== 'hidden' &&
               !(r.top > z.bottom || r.bottom < z.top ||
                 r.left > z.right || r.right < z.left);
    }

questo funziona per me se cambio e.style.opacity > 0a (!e.style.opacity || e.style.opacity > 0)perché di default è la stringa vuota per me in FF.
Brett Zamir,

6

Partendo da questa grande risposta , puoi semplificarla ulteriormente con ES2015 +:

function isScrolledIntoView(el) {
  const { top, bottom } = el.getBoundingClientRect()
  return top >= 0 && bottom <= window.innerHeight
}

Se non ti interessa che la parte superiore esca dalla finestra e ti preoccupi solo che la parte inferiore sia stata visualizzata, questo può essere semplificato

function isSeen(el) {
  return el.getBoundingClientRect().bottom <= window.innerHeight
}

o anche il one-liner

const isSeen = el => el.getBoundingClientRect().bottom <= window.innerHeight

4

È possibile utilizzare il plug-in jquery "onScreen" per verificare se l'elemento si trova nella finestra corrente durante lo scorrimento. Il plugin imposta ": onScreen" del selettore su true quando il selettore appare sullo schermo. Questo è il link per il plugin che puoi includere nel tuo progetto. " http://benpickles.github.io/onScreen/jquery.onscreen.min.js "

Puoi provare l'esempio seguente che funziona per me.

$(document).scroll(function() {
    if($("#div2").is(':onScreen')) {
        console.log("Element appeared on Screen");
        //do all your stuffs here when element is visible.
    }
    else {
        console.log("Element not on Screen");
        //do all your stuffs here when element is not visible.
    }
});

Codice HTML:

<div id="div1" style="width: 400px; height: 1000px; padding-top: 20px; position: relative; top: 45px"></div> <br>
<hr /> <br>
<div id="div2" style="width: 400px; height: 200px"></div>

CSS:

#div1 {
    background-color: red;
}
#div2 {
    background-color: green;
}

3

Ho un tale metodo nella mia applicazione, ma non usa jQuery:

/* Get the TOP position of a given element. */
function getPositionTop(element){
    var offset = 0;
    while(element) {
        offset += element["offsetTop"];
        element = element.offsetParent;
    }
    return offset;
}

/* Is a given element is visible or not? */
function isElementVisible(eltId) {
    var elt = document.getElementById(eltId);
    if (!elt) {
        // Element not found.
        return false;
    }
    // Get the top and bottom position of the given element.
    var posTop = getPositionTop(elt);
    var posBottom = posTop + elt.offsetHeight;
    // Get the top and bottom position of the *visible* part of the window.
    var visibleTop = document.body.scrollTop;
    var visibleBottom = visibleTop + document.documentElement.offsetHeight;
    return ((posBottom >= visibleTop) && (posTop <= visibleBottom));
}

Modifica: questo metodo funziona bene con IE (almeno versione 6). Leggi i commenti per la compatibilità con FF.


2
Per qualche motivo document.body.scrollTop restituisce sempre 0 (su ff3). Modificarlo in var visibleTop = (document.documentElement.scrollTop? Document.documentElement.scrollTop: document.body.scrollTop);
yoavf,

Scusa per quella cosa. La mia applicazione deve essere eseguita solo in IE 6 (sì, non sono fortunato :(), quindi non l'ho mai provato in FF ...
Romain Linsolas,

Questa sarebbe la migliore risposta qui se fosse corretta. Correggi una delle tue righe a questo: var visibleBottom = visibleTop + window.innerHeight;non sto usando jQuery e mi hai aiutato a trovare la risposta corretta.
Bitterblue,

3

Se vuoi modificarlo per scorrere l'elemento all'interno di un altro div,

function isScrolledIntoView (elem, divID) 

{

    var docViewTop = $('#' + divID).scrollTop();


    var docViewBottom = docViewTop + $('#' + divID).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop)); 
}

3

Modificata la risposta accettata in modo che l'elemento debba avere la proprietà display impostata su qualcosa di diverso da "none" in modo che sia visibile.

function isScrolledIntoView(elem) {
   var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();

  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();
  var elemDisplayNotNone = $(elem).css("display") !== "none";

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop) && elemDisplayNotNone);
}

3

Ecco un modo per ottenere la stessa cosa usando Mootools, in orizzontale, verticale o entrambi.

Element.implement({
inVerticalView: function (full) {
    if (typeOf(full) === "null") {
        full = true;
    }

    if (this.getStyle('display') === 'none') {
        return false;
    }

    // Window Size and Scroll
    var windowScroll = window.getScroll();
    var windowSize = window.getSize();
    // Element Size and Scroll
    var elementPosition = this.getPosition();
    var elementSize = this.getSize();

    // Calculation Variables
    var docViewTop = windowScroll.y;
    var docViewBottom = docViewTop + windowSize.y;
    var elemTop = elementPosition.y;
    var elemBottom = elemTop + elementSize.y;

    if (full) {
        return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
            && (elemBottom <= docViewBottom) && (elemTop >= docViewTop) );
    } else {
        return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
    }
},
inHorizontalView: function(full) {
    if (typeOf(full) === "null") {
        full = true;
    }

    if (this.getStyle('display') === 'none') {
        return false;
    }

    // Window Size and Scroll
    var windowScroll = window.getScroll();
    var windowSize = window.getSize();
    // Element Size and Scroll
    var elementPosition = this.getPosition();
    var elementSize = this.getSize();

    // Calculation Variables
    var docViewLeft = windowScroll.x;
    var docViewRight = docViewLeft + windowSize.x;
    var elemLeft = elementPosition.x;
    var elemRight = elemLeft + elementSize.x;

    if (full) {
        return ((elemRight >= docViewLeft) && (elemLeft <= docViewRight)
            && (elemRight <= docViewRight) && (elemLeft >= docViewLeft) );
    } else {
        return ((elemRight <= docViewRight) && (elemLeft >= docViewLeft));
    }
},
inView: function(full) {
    return this.inHorizontalView(full) && this.inVerticalView(full);
}});

3

Un esempio basato su questa risposta per verificare se un elemento è visibile al 75% (ovvero meno del 25% di esso è fuori dallo schermo).

function isScrolledIntoView(el) {
  // check for 75% visible
  var percentVisible = 0.75;
  var elemTop = el.getBoundingClientRect().top;
  var elemBottom = el.getBoundingClientRect().bottom;
  var elemHeight = el.getBoundingClientRect().height;
  var overhang = elemHeight * (1 - percentVisible);

  var isVisible = (elemTop >= -overhang) && (elemBottom <= window.innerHeight + overhang);
  return isVisible;
}

3

Ci sono oltre 30 risposte a questa domanda, e nessuna di esse utilizza la soluzione JS incredibilmente semplice e pura che ho usato. Non è necessario caricare jQuery solo per risolvere questo problema, come molti altri stanno spingendo.

Per sapere se l'elemento è all'interno del viewport, dobbiamo prima determinare la posizione degli elementi all'interno del corpo. Non abbiamo bisogno di farlo in modo ricorsivo come pensavo una volta. Invece, possiamo usare element.getBoundingClientRect().

pos = elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top;

Questo valore è la differenza Y tra la parte superiore dell'oggetto e la parte superiore del corpo.

Dobbiamo quindi dire se l'elemento è visibile. La maggior parte delle implementazioni chiede se l'intero elemento sia all'interno del viewport, quindi questo è ciò che tratteremo.

Prima di tutto, la posizione superiore della finestra è: window.scrollY.

Possiamo ottenere la posizione inferiore della finestra aggiungendo l'altezza della finestra nella sua posizione superiore:

var window_bottom_position = window.scrollY + window.innerHeight;

Consente di creare una semplice funzione per ottenere la posizione più alta dell'elemento:

function getElementWindowTop(elem){
    return elem && typeof elem.getBoundingClientRect === 'function' ? elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top : 0;
}

Questa funzione restituirà la posizione più alta dell'elemento all'interno della finestra o ritornerà 0se gli passi qualcosa di diverso da un elemento con il simbolo.getBoundingClientRect() metodo. Questo metodo esiste da molto tempo, quindi non dovresti preoccuparti che il tuo browser non lo supporti.

Ora, la posizione più alta del nostro elemento è:

var element_top_position = getElementWindowTop(element);

E la posizione in basso dell'elemento è:

var element_bottom_position = element_top_position + element.clientHeight;

Ora possiamo determinare se l'elemento è all'interno della finestra controllando se la posizione inferiore dell'elemento è inferiore alla posizione superiore della finestra e controllando se la posizione superiore dell'elemento è più alta della posizione inferiore della finestra:

if(element_bottom_position >= window.scrollY 
&& element_top_position <= window_bottom_position){
    //element is in view
else
    //element is not in view

Da lì, puoi eseguire la logica per aggiungere o rimuovere una in-viewclasse sul tuo elemento, che puoi successivamente gestire con effetti di transizione nel tuo CSS.

Sono assolutamente sorpreso di non aver trovato questa soluzione altrove, ma credo che questa sia la soluzione più pulita ed efficace e non richieda il caricamento di jQuery!


Spiegazione molto bella! Ma ci sono già risposte che fanno esattamente quello che fai, come la risposta di Ally
Domysee,

1
@Domysee Hmm, in qualche modo l'ho ignorato. Giusto. Grazie per averlo sottolineato però. È bello vederlo fatto in un altro modo.
WebWanderer,

3

Una versione più efficiente di questa risposta :

 /**
 * Is element within visible region of a scrollable container
 * @param {HTMLElement} el - element to test
 * @returns {boolean} true if within visible region, otherwise false
 */
 function isScrolledIntoView(el) {
      var rect = el.getBoundingClientRect();
      return (rect.top >= 0) && (rect.bottom <= window.innerHeight);
 }

2

Questo metodo restituirà true se qualsiasi parte dell'elemento è visibile sulla pagina. Nel mio caso ha funzionato meglio e potrebbe aiutare qualcun altro.

function isOnScreen(element) {
  var elementOffsetTop = element.offset().top;
  var elementHeight = element.height();

  var screenScrollTop = $(window).scrollTop();
  var screenHeight = $(window).height();

  var scrollIsAboveElement = elementOffsetTop + elementHeight - screenScrollTop >= 0;
  var elementIsVisibleOnScreen = screenScrollTop + screenHeight - elementOffsetTop >= 0;

  return scrollIsAboveElement && elementIsVisibleOnScreen;
}

2

Semplice modifica per div scorrevole (contenitore)

var isScrolledIntoView = function(elem, container) {
    var containerHeight = $(container).height();
    var elemTop = $(elem).position().top;
    var elemBottom = elemTop + $(elem).height();
    return (elemBottom > 0 && elemTop < containerHeight);
}

NOTA: questo non funziona se l'elemento è più grande del div scorrevole.


2

Ho adattato questa breve estensione della funzione jQuery, che puoi usare liberamente (licenza MIT).

/**
 * returns true if an element is visible, with decent performance
 * @param [scope] scope of the render-window instance; default: window
 * @returns {boolean}
 */
jQuery.fn.isOnScreen = function(scope){
    var element = this;
    if(!element){
        return;
    }
    var target = $(element);
    if(target.is(':visible') == false){
        return false;
    }
    scope = $(scope || window);
    var top = scope.scrollTop();
    var bot = top + scope.height();
    var elTop = target.offset().top;
    var elBot = elTop + target.height();

    return ((elBot <= bot) && (elTop >= top));
};

2

Ho scritto un componente per l'attività, progettato per gestire un gran numero di elementi in modo estremamente veloce (per un valore di <10 ms per 1000 elementi su un dispositivo mobile lento ).

Funziona con ogni tipo di contenitore di scorrimento a cui hai accesso - finestra, elementi HTML, iframe incorporato, finestra figlio generata - ed è molto flessibile in ciò che rileva ( visibilità totale o parziale , riquadro o casella di contenuto , zona di tolleranza personalizzata , ecc. ).

Un'enorme suite di test, per lo più generata automaticamente, assicura che funzioni come cross-browser pubblicizzato .

Provalo se ti piace: jQuery.isInView . Altrimenti, potresti trovare ispirazione nel codice sorgente, ad esempio qui .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.