Obter a altura visível de um div com jQuery

Eu preciso recuperar a altura visível de uma div dentro de uma área rolável. Eu me considero bastante decente com jQuery, mas isso está completamente me jogando fora.

Digamos que eu tenha um div vermelho em um wrapper preto:

No gráfico acima, a function jQuery retornaria 248, a parte visível do div.

Uma vez que o usuário rola a parte superior do div, como no gráfico acima, ele informaria 296.

Agora, depois que o usuário rolar a div, ele informaria novamente 248.

Obviamente, meus números não serão tão consistentes e claros como estão nessa demo, ou eu simplesmente codificaria esses números.

Eu tenho um pouco de teoria:

  • Obter a altura da janela
  • Obter a altura do div
  • Obter o deslocamento inicial do div a partir do topo da janela
  • Obter o deslocamento como o usuário rola.
    • Se o deslocamento for positivo, significa que a parte superior da div ainda está visível.
    • se for negativo, a parte superior da div foi eclipsada pela janela. Nesse ponto, o div pode estar ocupando toda a altura da janela ou a parte inferior da div pode estar mostrando
    • Se a parte inferior da div estiver aparecendo, calcule a lacuna entre ela e a parte inferior da janela.

Parece bem simples, mas eu simplesmente não consigo envolver minha cabeça nisso. Eu vou tomar outro crack amanhã de manhã; Eu apenas imaginei que alguns de vocês gênios poderiam ajudar.

Obrigado!

ATUALIZAÇÃO: Eu descobri isso por conta própria, mas parece que uma das respostas abaixo é mais elegante, então vou usar isso em vez disso. Para os curiosos, eis o que eu criei:

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

Aqui está um conceito rápido e sujo. Basicamente compara o offset().top do elemento ao topo da janela, e o offset().top + height() na parte inferior da janela:

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

Exemplo de violino

edit – pequena atualização para também executar a lógica quando a janela está sendo redimensionada.

Calcular a quantidade de px que um elemento (altura) está na viewport

Demo violino

Esta pequena function retornará a quantidade de px um elemento é visível na viewport (vertical):

 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, Ht) : Math.min(b, H)); } 

Use como:

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

é isso aí.


.inViewport() jQuery .inViewport()

jsFiddle demo

a partir do acima, você pode extrair a lógica e criar um plugin como este:

 /** * inViewport jQuery plugin by Roko CB * 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, Ht) : Math.min(b, H))); } visPx(); $(win).on("resize scroll", visPx); }); }; }(jQuery, window)); 

Use como:

 $("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 

seus seletores ouvirão dinamicamente a scroll janela e resize mas também retornarão o valor inicial no DOM pronto através do primeiro argumento de function de retorno de chamada px .

Aqui está uma versão da abordagem de Rory acima, exceto escrita para funcionar como um plugin jQuery. Pode ter aplicabilidade mais geral nesse formato. Ótima resposta, Rory – obrigado!

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

Pode ser chamado com o seguinte:

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

jsFiddle

Intereting Posts