Cómo comprobar si un elemento está fuera de la pantalla

81

Necesito verificar con jQuery si un elemento DIV no se cae de la pantalla. Los elementos son visibles y se muestran según los atributos de CSS, pero podrían colocarse intencionalmente fuera de la pantalla por:

position: absolute; 
left: -1000px; 
top: -1000px;

No pude usar el :visibleselector jQuery ya que el elemento tiene una altura y un ancho distintos de cero.

No estoy haciendo nada elegante. Esta ubicación de posición absoluta es la forma en que mi marco Ajax implementa el ocultar / mostrar algunos widgets.

Max
fuente
También di una respuesta a esto en esta pregunta 'duplicada': stackoverflow.com/questions/5353934/…
Tokimon

Respuestas:

135

Depende de cuál sea su definición de "fuera de la pantalla". ¿Está dentro de la ventana gráfica o dentro de los límites definidos de su página?

Usando Element.getBoundingClientRect () puede detectar fácilmente si su elemento está o no dentro de los límites de su ventana gráfica (es decir, en pantalla o fuera de pantalla):

jQuery.expr.filters.offscreen = function(el) {
  var rect = el.getBoundingClientRect();
  return (
           (rect.x + rect.width) < 0 
             || (rect.y + rect.height) < 0
             || (rect.x > window.innerWidth || rect.y > window.innerHeight)
         );
};

Luego puede usar eso de varias maneras:

// returns all elements that are offscreen
$(':offscreen');

// boolean returned if element is offscreen
$('div').is(':offscreen');
escurridizo
fuente
2
Me gustó esto, pero se rompe si su elemento está dentro de un contenedor desplazable: un elemento en la parte inferior de un DIV de 2 pantallas de altura siempre estará "fuera de la pantalla" ya que la altura de la ventana es menor que el offsetTop del elemento.
Coderer
@scurker No pude hacer que esto funcione. Aquí está mi pregunta SO (con jsFiddle) sobre el problema: stackoverflow.com/questions/26004098/…
crashwap
¿Me equivoco al pensar que esto no ocurrirá si el ha posicionado al padre (absoluto o relativo) antes del cuerpo?
fekiri malek
@fekirimalek Tienes razón, he actualizado el ejemplo para dar cuenta de eso
scurker
7
Tenga en cuenta que actualmente (enero de 2017) esto no funcionará al menos en Chrome, porque Element.getBoundingClientRect () tiene propiedades superior, derecha, inferior e izquierda en lugar de x e y.
Asu
18

Aquí hay un complemento de jQuery que permite a los usuarios probar si un elemento se encuentra dentro de la ventana gráfica visible del navegador, teniendo en cuenta la posición de desplazamiento del navegador.

$('#element').visible();

También puede comprobar la visibilidad parcial:

$('#element').visible( true);

Un inconveniente es que solo funciona con posicionamiento / desplazamiento vertical, aunque debería ser bastante fácil agregar posicionamiento horizontal a la mezcla.

Sam Sehnert
fuente
Este es un complemento MUY ligero. Pude obtener una barra de navegación fija al desplazarse hacia arriba y funcionar de manera receptiva a los pocos minutos de agregarla. Gran sugerencia.
Nappstir
Este complemento es muy ligero y bastante fácil de implementar. Resolvió el problema que tenía con los submenús.
Theo Orphanos
9

No es necesario un complemento para verificar si está fuera del puerto de visualización.

var w = Math.max(document.documentElement.clientWidth, window.innerWidth || 0)
var h = Math.max(document.documentElement.clientHeight, window.innerHeight || 0)
var d = $(document).scrollTop();

$.each($("div"),function(){
    p = $(this).position();
    //vertical
    if (p.top > h + d || p.top > h - d){
        console.log($(this))
    }
    //horizontal
    if (p.left < 0 - $(this).width() || p.left > w){
        console.log($(this))
    }
});
Simon Hudin
fuente
1
Esto funcionaría si usara en $(this).offsetlugar de $this.position. En este momento, solo está calculando la distancia desde su padre, que podría ser un div que lo envuelva perfectamente.
Ryan Shillington
7

Bueno ... He encontrado algunos problemas en cada solución propuesta aquí.

  • Debería poder elegir si desea que todo el elemento esté en la pantalla o solo una parte de él.
  • Las soluciones propuestas fallan si el elemento es más alto / más ancho que la ventana y cubre un poco la ventana del navegador.

Aquí está mi solución que incluye la jQuery .fnfunción de instancia y expression. He creado más variables dentro de mi función de las que podría, pero para problemas lógicos complejos, me gusta dividirlos en partes más pequeñas y con nombres claros.

Estoy usando un getBoundingClientRectmétodo que devuelve la posición del elemento en relación con la ventana gráfica, por lo que no necesito preocuparme por la posición de desplazamiento

Uso :

$(".some-element").filter(":onscreen").doSomething();
$(".some-element").filter(":entireonscreen").doSomething();
$(".some-element").isOnScreen(); // true / false
$(".some-element").isOnScreen(true); // true / false (partially on screen)
$(".some-element").is(":onscreen"); // true / false (partially on screen)
$(".some-element").is(":entireonscreen"); // true / false 

Fuente :

$.fn.isOnScreen = function(partial){

    //let's be sure we're checking only one element (in case function is called on set)
    var t = $(this).first();

    //we're using getBoundingClientRect to get position of element relative to viewport
    //so we dont need to care about scroll position
    var box = t[0].getBoundingClientRect();

    //let's save window size
    var win = {
        h : $(window).height(),
        w : $(window).width()
    };

    //now we check against edges of element

    //firstly we check one axis
    //for example we check if left edge of element is between left and right edge of scree (still might be above/below)
    var topEdgeInRange = box.top >= 0 && box.top <= win.h;
    var bottomEdgeInRange = box.bottom >= 0 && box.bottom <= win.h;

    var leftEdgeInRange = box.left >= 0 && box.left <= win.w;
    var rightEdgeInRange = box.right >= 0 && box.right <= win.w;


    //here we check if element is bigger then window and 'covers' the screen in given axis
    var coverScreenHorizontally = box.left <= 0 && box.right >= win.w;
    var coverScreenVertically = box.top <= 0 && box.bottom >= win.h;

    //now we check 2nd axis
    var topEdgeInScreen = topEdgeInRange && ( leftEdgeInRange || rightEdgeInRange || coverScreenHorizontally );
    var bottomEdgeInScreen = bottomEdgeInRange && ( leftEdgeInRange || rightEdgeInRange || coverScreenHorizontally );

    var leftEdgeInScreen = leftEdgeInRange && ( topEdgeInRange || bottomEdgeInRange || coverScreenVertically );
    var rightEdgeInScreen = rightEdgeInRange && ( topEdgeInRange || bottomEdgeInRange || coverScreenVertically );

    //now knowing presence of each edge on screen, we check if element is partially or entirely present on screen
    var isPartiallyOnScreen = topEdgeInScreen || bottomEdgeInScreen || leftEdgeInScreen || rightEdgeInScreen;
    var isEntirelyOnScreen = topEdgeInScreen && bottomEdgeInScreen && leftEdgeInScreen && rightEdgeInScreen;

    return partial ? isPartiallyOnScreen : isEntirelyOnScreen;

};

$.expr.filters.onscreen = function(elem) {
  return $(elem).isOnScreen(true);
};

$.expr.filters.entireonscreen = function(elem) {
  return $(elem).isOnScreen(true);
};
pie6k
fuente
1
Obtengo make_footer_down.js: 8 Uncaught TypeError: No se puede leer la propiedad 'getBoundingClientRect' de undefined al intentar usar sus funciones allí.
Ludvig W
Hola Lurr ... Lo intenté con $ ("# divId"). IsOnScreen (true); donde 'divId' estaba fuera de la pantalla y me devolvió 'falso'; entonces, siento que está funcionando
Anirban
1
  • Obtenga la distancia desde la parte superior del elemento dado
  • Agregue la altura del mismo elemento dado. Esto le dirá el número total desde la parte superior de la pantalla hasta el final del elemento dado.
  • Entonces todo lo que tiene que hacer es restar eso de la altura total del documento

    jQuery(function () {
        var documentHeight = jQuery(document).height();
        var element = jQuery('#you-element');
        var distanceFromBottom = documentHeight - (element.position().top + element.outerHeight(true));
        alert(distanceFromBottom)
    });
    
usuario5294803
fuente
-1

Puede verificar la posición del div usando $(div).position()y verificar si las propiedades del margen izquierdo y superior son menores que 0:

if($(div).position().left < 0 && $(div).position().top < 0){
    alert("off screen");
}
Troy Barlow
fuente
2
¿Qué pasa si el div no es negativo fuera de la vista?
dude