Ottieni l'altezza visibile di un div con jQuery


86

Devo recuperare l'altezza visibile di un div all'interno di un'area scorrevole. Mi considero abbastanza decente con jQuery, ma questo mi sta completamente buttando fuori.

Diciamo che ho un div rosso all'interno di un wrapper nero:

Nel grafico sopra, la funzione jQuery restituirebbe 248, la parte visibile del div.

Una volta che l'utente scorre oltre la parte superiore del div, come nel grafico sopra, riporterà 296.

Ora, una volta che l'utente ha passato il div, riporterà di nuovo 248.

Ovviamente i miei numeri non saranno così coerenti e chiari come lo sono in questa demo, o farei semplicemente un codice per quei numeri.

Ho un po 'di teoria:

  • Prendi l'altezza della finestra
  • Ottieni l'altezza del div
  • Ottieni l'offset iniziale del div dalla parte superiore della finestra
  • Ottieni l'offset mentre l'utente scorre.
    • Se l'offset è positivo, significa che la parte superiore del div è ancora visibile.
    • se è negativo, la parte superiore del div è stata eclissata dalla finestra. A questo punto, il div potrebbe occupare l'intera altezza della finestra o potrebbe essere visualizzata la parte inferiore del div
    • Se la parte inferiore del div è visibile, calcola lo spazio tra essa e la parte inferiore della finestra.

Sembra piuttosto semplice, ma non riesco a capirlo. Domani mattina prenderò un altro crack; Ho solo pensato che alcuni di voi geni potessero essere in grado di aiutare.

Grazie!

AGGIORNAMENTO: L'ho capito da solo, ma sembra che una delle risposte seguenti sia più elegante, quindi la userò invece. Per i curiosi, ecco cosa ho pensato:

$(document).ready(function() {
    var windowHeight = $(window).height();
    var overviewHeight = $("#overview").height();
    var overviewStaticTop = $("#overview").offset().top;
    var overviewScrollTop = overviewStaticTop - $(window).scrollTop();
    var overviewStaticBottom = overviewStaticTop + $("#overview").height();
    var overviewScrollBottom = windowHeight - (overviewStaticBottom - $(window).scrollTop());
    var visibleArea;
    if ((overviewHeight + overviewScrollTop) < windowHeight) {
        // alert("bottom is showing!");
        visibleArea = windowHeight - overviewScrollBottom;
        // alert(visibleArea);
    } else {
        if (overviewScrollTop < 0) {
            // alert("is full height");
            visibleArea = windowHeight;
            // alert(visibleArea);
        } else {
            // alert("top is showing");
            visibleArea = windowHeight - overviewScrollTop;
            // alert(visibleArea);
        }
    }
});

Vorrei esaminare le unità vh. 1vh = 1/100 dell'altezza del viewport. Probabilmente troverai una soluzione con quello. Trova l'altezza della finestra, l'altezza dell'elemento, la posizione degli elementi e la posizione di scorrimento e calcola di conseguenza.
davidcondrey

Supponendo che ci sia un margine sul DIV interno, dire "10px" tutt'intorno. Rileverei l'altezza di scorrimento per vedere se è passato "10", quindi otterrei solo l'altezza dell'elemento genitore, la sottrarre in base all'altezza di scorrimento.

Se tutto il resto fallisce, mi sono appena imbattuto in questo script che sembra possa servire allo scopo di cui hai bisogno: larsjung.de/fracs
davidcondrey

Risposte:


57

Ecco un concetto veloce e sporco. Fondamentalmente confronta la offset().topparte dell'elemento con la parte superiore della finestra e la offset().top + height()parte inferiore della finestra:

function getVisible() {    
    var $el = $('#foo'),
        scrollTop = $(this).scrollTop(),
        scrollBot = scrollTop + $(this).height(),
        elTop = $el.offset().top,
        elBottom = elTop + $el.outerHeight(),
        visibleTop = elTop < scrollTop ? scrollTop : elTop,
        visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
    $('#notification').text(visibleBottom - visibleTop);
}

$(window).on('scroll resize', getVisible);

Violino di esempio

modifica - piccolo aggiornamento per eseguire anche la logica quando la finestra viene ridimensionata.


Ho problemi a impostarlo per più messaggi divsenza semplicemente ripetere il codice. C'è un modo per fare questo?
JacobTheDev

2
@Rev ecco qui: jsfiddle.net/b5DGj/1 . Ho separato ogni elemento dalla sua chiamata di funzione. Potresti anche andare oltre e definire un plugin per farlo per te.
Rory McCrossan

Ho riscritto leggermente l'approccio di @ RoryMcCrossan per funzionare come plug-in jQuery e l'ho pubblicato come risposta di seguito: potrebbe avere un'applicabilità più generale in quel formato.
Michael.Lumley

A volte un elemento può essere parzialmente nascosto a causa di un overflow o di elementi padre, indipendentemente dalla "finestra"
Nadav B

55

Calcola la quantità di px di un elemento (altezza) nella finestra

Demo di violino

Questa piccola funzione restituirà la quantità di pxun elemento è visibile nella (verticale) Viewport :

function inViewport($el) {
    var elH = $el.outerHeight(),
        H   = $(window).height(),
        r   = $el[0].getBoundingClientRect(), t=r.top, b=r.bottom;
    return Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H));
}

Usa come:

$(window).on("scroll resize", function(){
  console.log( inViewport($('#elementID')) ); // n px in viewport
});

questo è tutto.


jQuery .inViewport()Plugin

jsFiddle demo

da quanto sopra puoi estrarre la logica e creare un plugin come questo:

/**
 * inViewport jQuery plugin by Roko C.B.
 * http://stackoverflow.com/a/26831113/383904
 * Returns a callback function with an argument holding
 * the current amount of px an element is visible in viewport
 * (The min returned value is 0 (element outside of viewport)
 */
;(function($, win) {
  $.fn.inViewport = function(cb) {
     return this.each(function(i,el) {
       function visPx(){
         var elH = $(el).outerHeight(),
             H = $(win).height(),
             r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
         return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));  
       }
       visPx();
       $(win).on("resize scroll", visPx);
     });
  };
}(jQuery, window));

Usa come:

$("selector").inViewport(function(px) {
  console.log( px ); // `px` represents the amount of visible height
  if(px > 0) {
    // do this if element enters the viewport // px > 0
  }else{
    // do that if element exits  the viewport // px = 0
  }
}); // Here you can chain other jQuery methods to your selector

i selettori ascolteranno dinamicamente la finestra scrolle resizerestituiranno anche il valore iniziale su DOM pronto attraverso il primo argomento della funzione di callback px.


Per lavorare su Android Chrome potrebbe essere necessario aggiungere <meta name="viewport" content="width=your_size">nella sezione html head.
userlond

@userlond grazie per il tuo contributo, ma non sono sicuro che content="width=1259"possa essere adatto alla maggioranza. Hai provato content="width=device-width, initial-scale=1"invece?
Roko C. Buljan

Il sito ha un modello legacy con larghezza fissa e non risponde ... Penso che il tuo suggerimento andrà bene per la maggioranza. Quindi, per chiarire: se la soluzione di Roko C.Buljan non funziona, prova ad aggiungere una <meta name="viewport" content="your_content">dichiarazione :)
userlond

Questo è così fantastico e così vicino a quello che stavo cercando. Come posso calcolare la distanza dal fondo degli elementi al fondo della finestra? Quindi posso caricare più contenuti prima che tu veda la fine del contenuto. Ad esempio, se elBottom <200 da windowBot, attiva AJAX.
Thom

1
@Thom beh, il metodo sopra non restituisce altri valori specifici (può essere espanso per restituire più cose oltre a visible height pxun oggetto, come un oggetto. Vedi questo violino per un'idea del genere: jsfiddle.net/RokoCB/6xjq5gyy (open developer console per vedere i log)
Roko C. Buljan

11

Ecco una versione dell'approccio di Rory sopra, tranne che scritto per funzionare come plugin jQuery. Potrebbe avere un'applicabilità più generale in quel formato. Ottima risposta, Rory - grazie!

$.fn.visibleHeight = function() {
    var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop;
    scrollTop = $(window).scrollTop();
    scrollBot = scrollTop + $(window).height();
    elTop = this.offset().top;
    elBottom = elTop + this.outerHeight();
    visibleTop = elTop < scrollTop ? scrollTop : elTop;
    visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
    return visibleBottom - visibleTop
}

Può essere chiamato con quanto segue:

$("#myDiv").visibleHeight();

jsFiddle


2
Non lavorare nel caso in cui la finestra diventa più grande e il blocco può adattarsi. Ecco perché dobbiamo reimpostare l'altezza del blocco: $ (this) .css ('height', ''); jsfiddle.net/b5DGj/144
Max Koshel
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.