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

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

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

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

我没有做什么花哨的事。这种绝对位置布局是我的 阿贾克斯框架实现某些小部件的 hide/show 的方式。

140784 次浏览

You could check the position of the div using $(div).position() and check if the left and top margin properties are less than 0 :

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

Depends on what your definition of "offscreen" is. Is that within the viewport, or within the defined boundaries of your page?

Using Element.getBoundingClientRect() you can easily detect whether or not your element is within the boundries of your viewport (i.e. onscreen or offscreen):

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

You could then use that in several ways:

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


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

There's a jQuery plugin here which allows users to test whether an element falls within the visible viewport of the browser, taking the browsers scroll position into account.

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

You can also check for partial visibility:

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

One drawback is that it only works with vertical positioning / scrolling, although it should be easy enough to add horizontal positioning into the mix.

I know this is kind of late but this plugin should work. http://remysharp.com/2009/01/26/element-in-view-event-plugin/

$('p.inview').bind('inview', function (event, visible) {
if (visible) {
$(this).text('You can see me!');
} else {
$(this).text('Hidden again');
}

No need for a plugin to check if outside of view port.

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

Well... I've found some issues in every proposed solution here.

  • You should be able to choose if you want entire element to be on screen or just any part of it
  • Proposed solutions fails if element is higher/wider than window and kinda covers browser window.

Here is my solution that include jQuery .fn instance function and expression. I've created more variables inside my function than I could, but for complex logical problem I like to divide it into smaller, clearly named pieces.

I'm using getBoundingClientRect method that returns element position relatively to the viewport so I don't need to care about scroll position

Useage:

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

Source:

$.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);
};
  • Get the distance from the top of the given element
  • Add the height of the same given element. This will tell you the total number from the top of the screen to the end of the given element.
  • Then all you have to do is subtract that from total document height

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

Although the original poster has asked for a JQuery solution, they have also added a JavaScript tag on the question which permits adding this more modern solution as well:

TLDR: Use the IntersectionObserver API.

Here are two sandboxes I've made both in vanilla JavaScript and in React to show this in working examples:

  1. Vanilla JavaScript example sandbox
  2. React example sandbox (uses the react-intersection-observer NPM module)

A bit longer answer: It's been more than 10 years since this question was asked and at that time using these JQuery solutions made sense, but today we don't need JQuery for such need anymore:

The Intersection Observer API provides a way to observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport.

It's very easy to use, first create an observer and pass it what you want to do when it's triggered (a callback function), and also optionally pass an options object too, e.g., in the case of this question, we'll need the threshold option with value of 1 to make sure the element is completely within the viewport, and if not, then we'll know that it's "offscreen":

const doable = () => {
//do something
}
const observer = new IntersectionObserver(doable, { threshold: 1 });

Now call the observe() method of it and pass the element you want to observe to it:

observer.observe(observee)