¿Cómo verificar si el elemento es visible después del desplazamiento?

1170

Estoy cargando elementos a través de AJAX. Algunos de ellos solo son visibles si se desplaza hacia abajo en la página.
¿Hay alguna manera de saber si un elemento está ahora en la parte visible de la página?

yoavf
fuente
42
quiere decir que quiere un método para saber si un elemento dado se muestra en la ventana del navegador o si el usuario necesita desplazarse para verlo.
Romain Linsolas
1
Para verificar si un elemento es completamente visible en un contenedor, simplemente agregue un parámetro selector adicional y reutilice el código elem para él. Library.IsElementVisibleInContainer = function (elementSelector, containerSelector) { var containerViewTop = $(containerSelector).offset().top; var containerViewBottom = containerViewTop + $(containerSelector).height();
Lifes
1
Todas las respuestas activarán el reflujo, por lo que podría ser un cuello de botella, grita usar IntersectionObserver si es compatible. Tendrá un mejor rendimiento en los navegadores modernos,
jcubic

Respuestas:

1259

Esto debería funcionar:

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

Función de utilidad simple Esto le permitirá llamar a una función de utilidad que acepte el elemento que está buscando y si desea que el elemento esté totalmente a la vista o parcialmente.

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');
}
Scott Dowding
fuente
52
Tenga en cuenta que esto solo funciona si el documento es el elemento que se está desplazando, es decir, no está verificando la visibilidad de algún elemento dentro de un panel interno desplazable.
Andrew B.
8
¿Cómo agregar un pequeño desplazamiento?
Jürgen Paul
55
Sólo funcionaba cuando utilicé window.innerHeightlugar
Cristiano Schnorr
2
Por lo elemTopque usé $(elem).position().topy por lo elemBottomque usé elemTop + $(elem).outerHeight(true).
Sarah Vessels
13
Para: "Cualquier parte del elemento en vista", usé: (((elemTop> = docViewTop) && (elemTop <= docViewBottom)) || ((elemBottom> = docViewTop) && (elemBottom <= docViewBottom)))
Grizly
415

Esta respuesta en vainilla:

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;
}
Bravedick
fuente
27
no debería ser esto isVisible = elementTop < window.innerHeight && elementBottom >= 0? De lo contrario, un elemento medio en la pantalla devuelve falso.
gman
77
No. compruebo si algún elemento es completamente visible en la página. si desea verificar la visibilidad de alguna parte, puede personalizar este fragmento.
bravedick
15
Encuentro que esta respuesta funciona mejor que la respuesta elegida. Más simple también.
Adam Venezia
12
En comparación con la respuesta aprobada, esto funciona muchísimo mejor con cientos de elementos.
ncla
55
ver un pequeño violín que demuestra aquí - jsfiddle.net/shaaraddalvi/4rp09jL0
upInCloud
122

Actualización: use IntersectionObserver


El mejor método que he encontrado hasta ahora es el complemento jQuery aparece . Funciona de maravilla.

Imita un evento personalizado de "aparición", que se dispara cuando un elemento se desplaza a la vista o de otra manera se vuelve visible para el usuario.

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

Este complemento se puede utilizar para evitar solicitudes innecesarias de contenido oculto o fuera del área visible.

Joe Lencioni
fuente
30
Este es un complemento genial, sin duda, pero no responde la pregunta.
Jon Adams
55
Si bien el complemento jQuery-seem es bueno para el contenido en el área de la página principal, desafortunadamente tiene problemas con los divs de desplazamiento de tamaño fijo con desbordamiento. El evento puede dispararse prematuramente cuando el elemento enlazado está dentro del área visible de la página pero fuera del área visible del div y luego no disparar como se esperaba cuando el elemento aparece en el div.
Peter
17
¿Hay un complemento para desaparecer?
Shamoon
3
@Shamoon verifica la fuente del appear pluginy probablemente solo necesites agregar un !lugar para obtener un disappearcomplemento.
Lucky Soni
55
Como nota, esto no funciona con jQuery 1.11.X github.com/morr/jquery.appear/issues/37
Jason Parham
86

Aquí está mi solución de JavaScript pura que funciona si también está oculta dentro de un contenedor desplazable.

Demostración aquí (intente cambiar el tamaño de la ventana también)

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

EDITAR 2016-03-26: He actualizado la solución para tener en cuenta el desplazamiento más allá del elemento para que esté oculto encima de la parte superior del contenedor desplazable. EDITAR 2018-10-08: actualizado para manejar cuando se desplaza fuera de la vista sobre la pantalla.

Aliado
fuente
gracias, tal vez sea mejor return top <= document.documentElement.clientHeight && top >= 0;
Yousef Salimpour
16
+1 Esta fue la única respuesta codificada (es decir, no de terceros) que tiene en cuenta la naturaleza recursiva de los elementos. Me he expandido para manejar el desplazamiento horizontal, vertical y de página: jsfiddle.net/9nuqpgqa
Pebbl
3
Esta solución solo verifica la parte superior del elemento. Si el primer píxel superior es visible, volverá verdadero incluso si el resto del elemento no está visible. Para verificar si todo el elemento está visible, también debe verificar la propiedad inferior.
Wojciech Jakubas
2
Sí, ordenado! Se usa para ayudar a escribir esta respuesta (con crédito como comentario js).
Roamer-1888
Desaparecido ; después del segundo "retorno falso" en el bucle
Mikhail Ramendik
46

Uso de IntersectionObserver API (nativo en navegadores modernos)

Es fácil y eficiente determinar si un elemento es visible en la vista o en cualquier contenedor desplazable, utilizando un observador .

Se scrollelimina la necesidad de adjuntar un evento y verificar manualmente la devolución de llamada del evento, por lo tanto, la eficiencia:

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


Ver tabla de soporte de navegadores (no es compatible con IE / Safari)

vsync
fuente
44
¡Gracias! Esto funciona para mí y también funcionó
Matt Wilson
Con mucho, la mejor solución. Trabajó en IE11 sin polyfill!
Fabian von Ellerts
Tenga en cuenta que este TODAVÍA no es compatible con iOS / macOS Safari, desafortunadamente. Asegúrate de revisar los problemas de rendimiento si eliges polyfill, ese es un gran grupo de usuarios
Leland
@Leland: depende del proyecto. Para todos mis proyectos, este es un grupo de 0 usuarios absolutos. No construyo sitios web sino sistema web;)
vsync
Estoy tratando de ejecutar esto en un bucle en varios elementos, pero no funciona. ¿Algunas ideas? Estoy agregando el elemento al objetivo en ese bucle.
Sascha Grindau
42

El complemento jQuery Waypoints va muy bien aquí.

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

Hay algunos ejemplos en el sitio del complemento .

Fedir RYKHTIK
fuente
3
Para mí solo funcionó con un desplazamiento $('#my-div').waypoint(function() { console.log('Hello there!'); }, { offset: '100%' });
leymannx
21

Qué tal si

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

Después de eso, puede activar lo que quiera una vez que el elemento esté a la vista de esta manera

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

Eso me funciona bien

webicy
fuente
1
Esto funciona para mí, pero utilicé la función, aparentemente más completa, isScrolledIntoView en stackoverflow.com/questions/487073/… :)
Meetai.com
3
Creo que debería ser $ (ventana) .scrollTop () <$ (elem) .offset (). Top + $ (elem) .height ();
Joven
Mi modificación sería así: `return $ (window) .scrollTop () + $ (window) .height ()> $ (elem) .offset (). Top + $ (elem) .height (); `
bubencode
16

Ajusté la función genial de Scott Dowding para mi requisito: esto se usa para encontrar si el elemento acaba de desplazarse a la pantalla, es decir, es el borde superior.

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

WebResourcesDepot escribió un script para cargar durante el desplazamiento que usa jQuery hace algún tiempo. Puede ver su demostración en vivo aquí . La esencia de su funcionalidad fue esta:

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

Vainilla simple para verificar si el elemento ( el) es visible en div desplazable ( holder)

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

Uso con jQuery:

var el = $('tr:last').get(0);
var holder = $('table').get(0);
isVisible =  isScrolledIntoView(el, holder);
Denis Matafonov
fuente
2
En esta era de aplicaciones de una sola página, se ha vuelto más común verificar si un elemento es visible dentro de otro elemento además de la ventana . Es por eso que este recibe mi voto positivo.
H Dog
8

isScrolledIntoView es una función muy necesaria, así que lo probé, funciona para elementos que no son más altos que la ventana gráfica, pero si el elemento es más grande que la ventana gráfica, no funciona. Para solucionar esto, cambie fácilmente la condición

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

a esto:

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

Ver demostración aquí: http://jsfiddle.net/RRSmQ/

Robert
fuente
8

La mayoría de las respuestas aquí no tienen en cuenta que un elemento también puede ocultarse porque se desplaza fuera de la vista de un div, no solo de toda la página.

Para cubrir esa posibilidad, básicamente debe verificar si el elemento está ubicado dentro de los límites de cada uno de sus padres.

Esta solución hace exactamente eso:

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

También le permite especificar en qué porcentaje debe estar visible en cada dirección.
No cubre la posibilidad de que pueda estar oculto debido a otros factores, como display: hidden.

Esto debería funcionar en todos los principales navegadores, ya que solo se usa getBoundingClientRect. Personalmente lo probé en Chrome e Internet Explorer 11.

Domysee
fuente
Gracias por este código. Me pregunto cómo agregaría el detector de eventos en el desplazamiento en este caso si tiene múltiples elementos desplazables anidados. Parece que agregar el oyente solo a la ventana no es suficiente, ¿tenemos que volver al padre superior para agregar el oyente a cada contenedor desplazable?
mr1031011
@ mr1031011 Debería ser posible agregar el controlador a la ventana y luego verificar el destino para identificar el contenedor que se desplazó.
Domysee
correcto, no funciona con el ejemplo dado por @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));
}
Pascal Gagneur
fuente
7

Aquí hay otra solución de 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>

Véalo en JSFiddle

Adrian P.
fuente
7

Esto considera cualquier relleno, borde o margen que tenga el elemento, así como elementos más grandes que la ventana gráfica.

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

Para llamarlo use algo como esto:

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

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

Hay un complemento para jQuery llamado inview que agrega un nuevo evento "inview".


Aquí hay un código para un complemento jQuery que no usa eventos:

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

Encontré esto en un comentario aquí ( http://remysharp.com/2009/01/26/element-in-view-event-plugin/ ) por un tipo llamado James

ness-EE
fuente
Por desgracia, jQuery inview ya no se mantiene y no funciona con las versiones actuales de jQuery.
mikemaccana
1
JQuery 1 es para soporte de navegador heredado, las nuevas características están en jQuery 2.
mikemaccana
El enlace no muestra el ejemplo ya que la página se ha actualizado.
Profesor de programación el
6

Necesitaba verificar la visibilidad en los elementos dentro del contenedor DIV desplazable

    //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);
    }
Pigmalión
fuente
esto funciona para mí si cambio el e.style.opacity > 0a (!e.style.opacity || e.style.opacity > 0)porque, por defecto, es la cadena vacía para mí en FF.
Brett Zamir
6

A partir de esta gran respuesta , puede simplificarla un poco más con ES2015 +:

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

Si no le importa que salga la parte superior de la ventana y solo le importa que se haya visto la parte inferior, esto puede simplificarse para

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

o incluso el one-liner

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

Puede utilizar el complemento jquery "en pantalla" para verificar si el elemento está en la ventana gráfica actual cuando se desplaza. El complemento establece el ": en pantalla" del selector en verdadero cuando el selector aparece en la pantalla. Este es el enlace para el complemento que puede incluir en su proyecto. " http://benpickles.github.io/onScreen/jquery.onscreen.min.js "

Puedes probar el siguiente ejemplo que funciona para mí.

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

Código 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;
}
Vasuki Dileep
fuente
3

Tengo un método de este tipo en mi aplicación, pero no utiliza 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));
}

Editar: este método funciona bien para IE (al menos la versión 6). Lea los comentarios para compatibilidad con FF.

Romain Linsolas
fuente
2
Por alguna razón, document.body.scrollTop siempre devuelve 0 (en ff3). Cámbielo a var visibleTop = (document.documentElement.scrollTop? Document.documentElement.scrollTop: document.body.scrollTop);
yoavf
Lo siento por eso. Mi aplicación debe ejecutarse solo en IE 6 (sí, no tengo suerte :(), así que nunca probé esto en FF ...
Romain Linsolas
Esta sería la mejor respuesta aquí si fuera correcta. Corrija una de sus líneas para esto: var visibleBottom = visibleTop + window.innerHeight;no estoy usando jQuery y me ayudó a encontrar la respuesta correcta.
Bitterblue
3

Si desea ajustar esto para desplazar el elemento dentro de otro 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)); 
}
Samiya Akhtar
fuente
3

Modificó la respuesta aceptada para que el elemento tenga que tener su propiedad de visualización configurada en algo diferente a "ninguno" para que la calidad sea visible.

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);
}
evanmcd
fuente
3

Aquí hay una manera de lograr lo mismo usando Mootools, en horizontal, vertical o ambos.

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);
}});
bmlkc
fuente
3

Un ejemplo basado en esta respuesta para verificar si un elemento es visible en un 75% (es decir, menos del 25% está fuera de la pantalla).

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;
}
Brendan Nee
fuente
3

Hay más de 30 respuestas a esta pregunta, y ninguna de ellas utiliza la solución JS increíblemente simple y pura que he estado usando. No es necesario cargar jQuery solo para resolver esto, ya que muchos otros están presionando.

Para saber si el elemento está dentro de la ventana gráfica, primero debemos determinar la posición de los elementos dentro del cuerpo. No necesitamos hacer esto de forma recursiva como alguna vez pensé. En cambio, podemos usar element.getBoundingClientRect().

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

Este valor es la diferencia Y entre la parte superior del objeto y la parte superior del cuerpo.

Entonces debemos decir si el elemento está a la vista. La mayoría de las implementaciones preguntan si el elemento completo está dentro de la ventana gráfica, por lo que esto es lo que cubriremos.

En primer lugar, la posición superior de la ventana es: window.scrollY.

Podemos obtener la posición inferior de la ventana agregando la altura de la ventana a su posición superior:

var window_bottom_position = window.scrollY + window.innerHeight;

Vamos a crear una función simple para obtener la posición superior del elemento:

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

Esta función devolverá la posición superior del elemento dentro de la ventana o volverá 0si le pasa algo más que un elemento con el .getBoundingClientRect()método. Este método ha existido durante mucho tiempo, por lo que no debería tener que preocuparse de que su navegador no lo admita.

Ahora, la posición superior de nuestro elemento es:

var element_top_position = getElementWindowTop(element);

Y la posición inferior del elemento es:

var element_bottom_position = element_top_position + element.clientHeight;

Ahora podemos determinar si el elemento está dentro de la ventana gráfica al verificar si la posición inferior del elemento es más baja que la posición superior de la ventana gráfica y al verificar si la posición superior del elemento es más alta que la posición inferior de la ventana gráfica:

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

A partir de ahí, puede realizar la lógica para agregar o eliminar una in-viewclase en su elemento, que luego puede manejar con efectos de transición en su CSS.

Estoy absolutamente asombrado de no haber encontrado esta solución en ningún otro lado, pero sí creo que es la solución más limpia y efectiva, ¡y no requiere que cargue jQuery!

WebWanderer
fuente
Muy buena explicación! Pero ya hay respuestas que hacen exactamente lo que haces, como la respuesta de Ally
Domysee
1
@Domysee Hmm, de alguna manera salté eso. Lo suficientemente justo. Gracias por señalar eso sin embargo. Es bueno ver esto hecho de otra manera.
WebWanderer
3

Una versión más eficiente de esta respuesta :

 /**
 * 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);
 }
John Doherty
fuente
2

Este método devolverá verdadero si alguna parte del elemento es visible en la página. Funcionó mejor en mi caso y puede ayudar a alguien más.

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;
}
Rafael García
fuente
2

Modificación simple para div desplazable (contenedor)

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: esto no funciona si el elemento es más grande que el div desplazable.

Derrick J Wippler
fuente
2

Adapte esta breve extensión de la función jQuery, que puede usar libremente (licencia 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));
};
Lorenz Lo Sauer
fuente
2

He escrito un componente para la tarea, diseñado para manejar grandes cantidades de elementos extremadamente rápido (con una sintonía de <10 ms para 1000 elementos en un móvil lento ).

Funciona con cada tipo de contenedor de desplazamiento al que tiene acceso: ventana, elementos HTML, iframe incrustado, ventana secundaria engendrada, y es muy flexible en lo que detecta ( visibilidad total o parcial , cuadro de borde o cuadro de contenido , zona de tolerancia personalizada , etc. )

Un conjunto de pruebas enorme, en su mayoría autogenerado, asegura que funcione como se anuncia, entre navegadores .

Pruébalo si quieres: jQuery.isInView . De lo contrario, puede encontrar inspiración en el código fuente, por ejemplo, aquí .

hashchange
fuente