如何检查元素是否在屏幕外


81

我需要使用jQuery检查DIV元素是否未脱离屏幕。这些元素是可见的,并根据CSS属性显示,但是可以通过以下方式有意地将其放置在屏幕外:

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

我不能使用jQuery:visible选择器,因为元素的高度和宽度都不为零。

我没有做任何幻想。这种绝对位置放置是我的Ajax框架实现某些小部件的隐藏/显示的方式。


对于这个“重复”问题,我也给出了答案:stackoverflow.com/questions/5353934/…–
Tokimon

Answers:


135

取决于您对“屏幕外”的定义。是在视口内还是在页面的定义边界内?

使用Element.getBoundingClientRect(),您可以轻松检测元素是否在视口的边界内(即屏幕上或屏幕外):

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

然后,您可以通过多种方式使用它:

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

// boolean returned if element is offscreen
$('div').is(':offscreen');

2
我喜欢这个,但是如果您的元素在可滚动容器内,它就会中断-高2个屏幕的DIV底部的元素将始终处于“屏幕外”状态,因为窗口高度小于该元素的offsetTop。
Coderer 2013年

@scurker我无法使它正常工作。这里是我的SO问题(用的jsfiddle)这个问题:stackoverflow.com/questions/26004098/...
crashwap

我在这里以为如果el将父母(绝对或亲戚)定位在身体之前不会是错误的?
fekiri malek '16

@fekirimalek是的,我已经更新了示例以说明这一点
scurker

7
请注意,目前(2017年1月)至少在Chrome上不起作用,因为Element.getBoundingClientRect()具有top,right,bottom和left属性,而不是x和y属性。
阿苏

18

这里有一个jQuery插件,允许用户在考虑浏览器滚动位置的情况下测试元素是否落在浏览器的可见视口内。

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

您还可以检查部分可见性:

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

一个缺点是,它仅适用于垂直定位/滚动,尽管添加水平定位应该很容易。


这是一个非常轻巧的插件。我能够在滚动时获得固定的导航栏,并在添加导航后的几分钟内做出响应。很棒的建议。
Nappstir

这个插件非常轻巧,很容易实现。解决了子菜单中的问题。
Theo Orphanos

9

无需插件即可检查视口之外。

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

1
如果您使用$(this).offset代替,则可以使用$this.position。现在,它只是在计算与父对象的距离,这可能是一个将其完美包裹的div。
Ryan Shillington

7

好吧...我在这里提出的每个解决方案中都发现了一些问题。

  • 您应该能够选择是要在屏幕上显示整个元素还是仅显示其中的任何一部分
  • 如果元素比窗口高/宽,并且覆盖了浏览器窗口,建议的解决方案将失败

这是我的解决方案,其中包括jQuery .fn实例函数和expression。我在函数中创建了比我更多的变量,但是对于复杂的逻辑问题,我喜欢将其分成更小的,名称明确的部分。

我正在使用getBoundingClientRect相对于视口返回元素位置的方法,所以我不需要关心滚动位置

使用方法

$(".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 

资料来源

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

1
我收到make_footer_down.js:8 Uncaught TypeError:尝试在其中使用ur函数时,无法读取未定义的属性'getBoundingClientRect'。
Ludvig W

嗨,Lurr ...我试过$(“#divId”)。isOnScreen(true); 其中“ divId”不在屏幕上,并且返回“ false”;所以,我觉得它在起作用
Anirban


1
  • 获取距给定元素顶部的距离
  • 添加相同给定元素的高度。这将告诉您从屏幕顶部到给定元素末尾的总数。
  • 然后,您要做的就是从文档总高度中减去

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

-1

您可以使用$(div).position()检查div的位置,并检查left和top margin属性是否小于0:

if($(div).position().left < 0 && $(div).position().top < 0){
    alert("off screen");
}

2
如果div在视野之外不是负数怎么办?
花花公子
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.