¿Cómo puedo saber si un elemento DOM es visible en la ventana gráfica actual?
¿Existe una forma eficaz de saber si un elemento DOM (en un documento HTML) está actualmente visible (aparece en la ventana gráfica )?
(La pregunta se refiere a Firefox).
Ahora la mayoría de los navegadores admiten el método getBoundingClientRect , que se ha convertido en la mejor práctica. Usar una respuesta antigua es muy lento, no preciso y tiene varios errores .
La solución seleccionada como correcta casi nunca es precisa .
Esta solución se probó en Internet Explorer 7 (y posteriores), iOS 5 (y posteriores), Safari, Android 2.0 (Eclair) y posteriores, BlackBerry, Opera Mobile e Internet Explorer Mobile 9 .
function isElementInViewport (el) {
// Special bonus for those using jQuery
if (typeof jQuery === "function" && el instanceof jQuery) {
el = el[0];
}
var rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /* or $(window).height() */
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /* or $(window).width() */
);
}
Cómo utilizar:
Puede estar seguro de que la función proporcionada anteriormente devuelve la respuesta correcta en el momento en que se llama, pero ¿qué pasa con la visibilidad del elemento de seguimiento como un evento?
Coloque el siguiente código en la parte inferior de su <body>
etiqueta:
function onVisibilityChange(el, callback) {
var old_visible;
return function () {
var visible = isElementInViewport(el);
if (visible != old_visible) {
old_visible = visible;
if (typeof callback == 'function') {
callback();
}
}
}
}
var handler = onVisibilityChange(el, function() {
/* Your code go here */
});
// jQuery
$(window).on('DOMContentLoaded load resize scroll', handler);
/* // Non-jQuery
if (window.addEventListener) {
addEventListener('DOMContentLoaded', handler, false);
addEventListener('load', handler, false);
addEventListener('scroll', handler, false);
addEventListener('resize', handler, false);
} else if (window.attachEvent) {
attachEvent('onDOMContentLoaded', handler); // Internet Explorer 9+ :(
attachEvent('onload', handler);
attachEvent('onscroll', handler);
attachEvent('onresize', handler);
}
*/
Si realiza alguna modificación DOM, por supuesto, puede cambiar la visibilidad de su elemento.
Directrices y errores comunes:
¿Quizás necesite realizar un seguimiento del zoom de la página o del pellizco del dispositivo móvil? jQuery debería manejar el navegador cruzado con zoom/pellizco ; de lo contrario, el primer o segundo enlace debería ayudarle.
Si modifica DOM , puede afectar la visibilidad del elemento. Deberías tomar control sobre eso y llamar handler()
manualmente. Lamentablemente, no tenemos ningún onrepaint
evento entre navegadores. Por otro lado, eso nos permite realizar optimizaciones y volver a verificar solo las modificaciones del DOM que pueden cambiar la visibilidad de un elemento.
Nunca lo uses solo dentro de jQuery $(document).ready() , porque no hay garantía de que se haya aplicado CSS en este momento. Su código puede funcionar localmente con su CSS en un disco duro, pero una vez colocado en un servidor remoto fallará.
Después DOMContentLoaded
de disparar, se aplican estilos , pero las imágenes aún no se cargan . Entonces, deberíamos agregar window.onload
un detector de eventos.
Aún no podemos captar el evento de zoom/pellizco.
El último recurso podría ser el siguiente código:
/* TODO: this looks like a very bad code */
setInterval(handler, 600);
Puede utilizar la increíble visibilidad de la página de funciones de la API HTML5 si le importa si la pestaña con su página web está activa y visible.
TODO: este método no maneja dos situaciones:
- Superposición usando
z-index
. - Usando
overflow-scroll
en el contenedor del elemento. - Pruebe algo nuevo: explicación de la API de Intersection Observer .
Actualización: el tiempo avanza y nuestros navegadores también. Esta técnica ya no se recomienda y debes usar la solución de Dan si no necesitas admitir la versión de Internet Explorer anterior a la 7.
Solución original (ahora desactualizada):
Esto comprobará si el elemento es completamente visible en la ventana gráfica actual:
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth)
);
}
Podrías modificar esto simplemente para determinar si alguna parte del elemento es visible en la ventana gráfica:
function elementInViewport2(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}