Preciso recuperar a altura visível de um div em uma área de rolagem. Eu me considero bastante decente com o jQuery, mas isso está me deixando completamente louco.
Digamos que eu tenha um div vermelho dentro de um invólucro preto:
No gráfico acima, a função jQuery retornaria 248, a parte visível do div.
Assim que o usuário rolar para além do topo do div, como no gráfico acima, ele reportará 296.
Agora, depois que o usuário rolar para além do div, ele relatará novamente 248.
Obviamente, meus números não serão tão consistentes e claros como são nesta demonstração, ou eu apenas codificaria para esses números.
Eu tenho um pouco de teoria:
- Obtenha a altura da janela
- Obtenha a altura do div
- Obtenha o deslocamento inicial do div do topo da janela
- Obtenha o deslocamento conforme o usuário rola.
- Se o deslocamento for positivo, significa que o topo da div ainda está visível.
- se for negativo, a parte superior do div foi eclipsada pela janela. Neste ponto, o div pode estar ocupando toda a altura da janela ou a parte inferior do div pode estar sendo exibida
- Se a parte inferior da div estiver aparecendo, descubra a lacuna entre ela e a parte inferior da janela.
Parece muito simples, mas simplesmente não consigo entender isso. Vou tentar outra vez amanhã de manhã; Achei que alguns de vocês, gênios, poderiam ajudar.
Obrigado!
ATUALIZAÇÃO: descobri isso sozinho, mas parece que uma das respostas abaixo é mais elegante, então usarei isso. Para os curiosos, aqui está 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);
}
}
});
fonte
Respostas:
Aqui está um conceito rápido e sujo. Basicamente, compara o
offset().top
do elemento com a parte superior da janela eoffset().top + height()
com a 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
editar - pequena atualização para também realizar a lógica quando a janela está sendo redimensionada.
fonte
div
s sem apenas repetir o código. Existe uma maneira de fazer isso?Calcule a quantidade de px de um elemento (altura) na janela de visualização
Demonstração de violino
Esta função minúscula retornará a quantidade de
px
um elemento que está visível na janela de visualização (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, H-t) : Math.min(b, H)); }
Use como:
$(window).on("scroll resize", function(){ console.log( inViewport($('#elementID')) ); // n px in viewport });
é isso aí.
.inViewport()
Plugin jQuerydemonstração jsFiddle
acima, você pode extrair a lógica e criar um plugin como este:
/** * 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));
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 janela
scroll
eresize
também retornarão o valor inicial no DOM pronto por meio do primeiro argumento da função de retorno de chamadapx
.fonte
<meta name="viewport" content="width=your_size">
a seção head html.content="width=1259"
adequa à maioria. Você já tentoucontent="width=device-width, initial-scale=1"
?<meta name="viewport" content="your_content">
declaração :)visible height px
, como um objeto. Veja este violino para essa ideia: jsfiddle.net/RokoCB/6xjq5gyy (console de desenvolvedor aberto para ver os registros)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
fonte