¿Cómo puedo saber si un elemento está visible en la ventana de visualización?

publicado por: Anonymous

Quiero saber si un elemento se encuentra visible en un momento dado en el viewport, es decir en la ventana de visualización del navegador, usando JavaScript/jQuery.

Por esta otra pregunta, sé que con .is(':visible') puedo averiguar si ese elemento está visible o no, pero eso no quiere decir que este dentro de la ventana de visualización (y por tanto invisible para el usuario), que es lo que yo quiero.

Por ejemplo: En el siguiente código se comprueba si un elemento está visible cuando se pulsa el botón; pero si realizamos scroll, bajamos hasta abajo de la página y volvemos a pulsar en el botón, nos sigue diciendo que sí lo está aunque el usuario ya no puede verlo.

_x000D_

_x000D_

$("button").on("click", function() {_x000D_
  alert($("#holamundo").is(":visible"));_x000D_
});

_x000D_

button {_x000D_
  position:fixed;_x000D_
  top:5px;_x000D_
  right:5px;_x000D_
}_x000D_
_x000D_
p {_x000D_
  margin-top: 800px;_x000D_
}

_x000D_

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>_x000D_
_x000D_
<button>¿Está "Hola Mundo" visible?</button>_x000D_
_x000D_
<div id="holamundo">Hola Mundo</div>_x000D_
_x000D_
<p>.</p>_x000D_
<p>.</p>

_x000D_

_x000D_

_x000D_

¿Existe alguna función propia o cómo se haría en JavaScript/jQuery para detectar si un elemento está visible Y en la ventana de visualización?

solución

Podríamos validar esto accediendo primero a los valores de la “ventana de visualización” , para esto se hace uso de scrollTop del objeto window para saber cuando se desplazó hacía abajo y el limite lo obtenemos de la suma del valor devuelvo por scrollTop + height de la ventana

Luego tendríamos que realizar el mismo procedimiento para el elemento , para esto emplearemos offset para las coordenadas y acceder a la propiedad top para luego obtener la altura del elemento también con height

Ya con estos valores validaríamos comparando , la función quedaría así:

_x000D_

_x000D_

function esVisible(elem){_x000D_
    /* Ventana de Visualización*/_x000D_
    var posTopView = $(window).scrollTop();_x000D_
    var posButView = posTopView + $(window).height();_x000D_
    /* Elemento a validar*/_x000D_
    var elemTop = $(elem).offset().top;_x000D_
    var elemBottom = elemTop + $(elem).height();_x000D_
    /* Comparamos los dos valores tanto del elemento como de la ventana*/_x000D_
    return ((elemBottom < posButView && elemBottom > posTopView) || (elemTop >posTopView && elemTop< posButView));_x000D_
}_x000D_
_x000D_
$("button").on("click", function() {_x000D_
  var ele = document.getElementById('holamundo');_x000D_
  console.log(esVisible(ele));_x000D_
});

_x000D_

button {_x000D_
  position:fixed;_x000D_
  top:5px;_x000D_
  right:5px;_x000D_
}_x000D_
_x000D_
p {_x000D_
  margin-top: 800px;_x000D_
}

_x000D_

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<button>¿Está "Hola Mundo" visible?</button>_x000D_
<div id="holamundo">Hola Mundo</div>_x000D_
<p>.</p>_x000D_
<p>.</p>

_x000D_

_x000D_

_x000D_

Update

Como recomendación de @Alvaro Montoro , Con el ejemplo anterior funcionaría pero height no tomará en cuenta el padding como sí lo hace outerheight

_x000D_

_x000D_

function esVisible(elem){_x000D_
    /* Ventana de Visualización*/_x000D_
    var posTopView = $(window).scrollTop();_x000D_
    var posButView = posTopView + $(window).height();_x000D_
    /* Elemento a validar*/_x000D_
    var elemTop = $(elem).offset().top;_x000D_
    var elemBottom = elemTop + $(elem).outerHeight();_x000D_
    /* Comparamos los dos valores tanto del elemento como de la ventana*/_x000D_
    return ((elemBottom < posButView && elemBottom > posTopView) || (elemTop >posTopView && elemTop< posButView));_x000D_
}_x000D_
_x000D_
$("button").on("click", function() {_x000D_
  var ele = document.getElementById('holamundo');_x000D_
  console.log(esVisible(ele));_x000D_
});

_x000D_

button {_x000D_
  position:fixed;_x000D_
  top:5px;_x000D_
  right:5px;_x000D_
}_x000D_
_x000D_
p {_x000D_
  margin-top: 800px;_x000D_
}_x000D_
#holamundo{_x000D_
    padding: 120px;_x000D_
    background: #ccc;_x000D_
}

_x000D_

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
<button>¿Está "Hola Mundo" visible?</button>_x000D_
_x000D_
<div id="holamundo">Hola Mundo</div>_x000D_
_x000D_
<p>.</p>_x000D_
<p>.</p>

_x000D_

_x000D_

_x000D_

Ejemplo empleando solo JavaScript

_x000D_

_x000D_

function esVisible(elem){_x000D_
    var posTopView = window.scrollY;_x000D_
    var posButView = posTopView + window.innerHeight;_x000D_
    var elemTop = elem.offsetTop;_x000D_
    var elemBottom = elemTop + elem.offsetHeight;_x000D_
    return ((elemBottom < posButView && elemBottom > posTopView) || (elemTop >posTopView && elemTop< posButView));_x000D_
}_x000D_
_x000D_
document.getElementById('btn').addEventListener("click", function(){_x000D_
    var ele = document.getElementById('holamundo');_x000D_
    console.log(esVisible(ele));_x000D_
});

_x000D_

button {_x000D_
  position:fixed;_x000D_
  top:5px;_x000D_
  right:5px;_x000D_
}_x000D_
_x000D_
p {_x000D_
  margin-top: 800px;_x000D_
}

_x000D_

<button id="btn">¿Está "Hola Mundo" visible?</button>_x000D_
<div id="holamundo">Hola Mundo</div>_x000D_
<p>.</p>_x000D_
<p>.</p>

_x000D_

_x000D_

_x000D_

Referencia en SO

Update

Otra opción sería utilizar la API IntersectionObserver() para saber si el elemento está visible
o no.

  • Crear el objeto de opciones con tres valores root , está propiedad determina el elemento donde se validará la visibilidad del elemento a observar,por defecto toma el viewport del navegador
    rootMargin, esta propiedad determina el margen que se incluirá en la evaluación de la visibilidad
    threshold , esta propiedad determina el porcentaje de visibilidad que se desea observar, el valor por defecto es 0 es decir que tan pronto como sea visible (1px mínimo),
    y 1 cuando el elemento esté completamente visible. esta propiedad se pueden pasar más de 1 parámetro, revisar la documentación. 🙂

  • Crear la instancia de IntersectionObserver, como primer parámetro un callback y como segundo parámetro el objeto de opciones

  • Asignar el observer al o los elementos a evaluar. Para el ejemplo solo uno con el id holamundo

Dentro del callback tendrá el parámetro entries que hará referencia a los elementos observados, (el ejemplo el elemento sería el indice 0), a través
de isIntersecting verificamos si está visible teniendo en cuenta las opciones, a partir de eso podemos realizar acciones según sea el caso.

_x000D_

_x000D_

function callback(entries,observer){_x000D_
  if(entries[0].isIntersecting){//verificamos si actualmente es visible_x000D_
    console.log("El elemento ya está visible...");_x000D_
  }else{_x000D_
    console.log("El elemento no es visible.");_x000D_
  }_x000D_
}_x000D_
var observer = new IntersectionObserver(callback, {});_x000D_
_x000D_
const element = document.querySelector('#holamundo');_x000D_
observer.observe(element);

_x000D_

.boxMargin {_x000D_
  width: 300px;_x000D_
  height: 400px;_x000D_
  border : 1px solid #aec;_x000D_
}

_x000D_

<div class="boxMargin"></div>_x000D_
<div class="boxMargin"></div>_x000D_
<div id="holamundo">Hola Mundo</div>_x000D_
<div class="boxMargin"></div>_x000D_
<div class="boxMargin"></div>

_x000D_

_x000D_

_x000D_

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *