关于javascript:如何在滚动后检查元素是否可见?

How to Check if element is visible after scrolling?

我正在通过Ajax加载元素。只有向下滚动页面时,其中一些才可见。我有没有办法知道元素现在是否在页面的可见部分?


这应该可以做到:

1
2
3
4
5
6
7
8
9
10
function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

简单效用函数这将允许您调用一个实用程序函数,该函数接受您要查找的元素,如果您希望元素完全在视图中或部分在视图中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function Utils() {

}

Utils.prototype = {
    constructor: Utils,
    isElementInView: function (element, fullyInView) {
        var pageTop = $(window).scrollTop();
        var pageBottom = pageTop + $(window).height();
        var elementTop = $(element).offset().top;
        var elementBottom = elementTop + $(element).height();

        if (fullyInView === true) {
            return ((pageTop < elementTop) && (pageBottom > elementBottom));
        } else {
            return ((elementTop <= pageBottom) && (elementBottom >= pageTop));
        }
    }
};

var Utils = new Utils();

用法

1
2
3
4
5
6
7
var isElementInView = Utils.isElementInView($('#flyout-left-container'), false);

if (isElementInView) {
    console.log('in view');
} else {
    console.log('out of view');
}


到目前为止,我找到的最好的方法是jquery显示插件。很有魅力。

Mimics a custom"appear" event, which fires when an element scrolls into view or otherwise becomes visible to the user.

1
2
3
$('#foo').appear(function() {
  $(this).text('Hello world');
});

This plugin can be used to prevent unnecessary requests for content that's hidden or outside the viewable area.


这是我的纯javascript解决方案,如果它也隐藏在可滚动容器中,它也可以工作。

这里演示(也尝试调整窗口大小)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var visibleY = function(el){
  var rect = el.getBoundingClientRect(), top = rect.top, height = rect.height,
    el = el.parentNode
  // Check if bottom of the element is off the page
  if (rect.bottom < 0) return false
  // Check its within the document viewport
  if (top > document.documentElement.clientHeight) return false
  do {
    rect = el.getBoundingClientRect()
    if (top <= rect.bottom === false) return false
    // Check if the element is out of view due to a container scrolling
    if ((top + height) <= rect.top) return false
    el = el.parentNode
  } while (el != document.body)
  return true
};

编辑2016-03-26:我已经更新了解决方案,考虑到滚动超过元素,所以它隐藏在可滚动容器的顶部。编辑2018-10-08:当滚动到屏幕上方的视图之外时更新为处理。


jquery waypoints插件在这里非常不错。

1
2
3
$('.entry').waypoint(function() {
   alert('You have scrolled to an entry.');
});

在插件的站点上有一些例子。


怎么样

1
2
3
function isInView(elem){
   return $(elem).offset().top - $(window).scrollTop() < $(elem).height() ;
}

之后,一旦元素出现在这样的视图中,您就可以触发您想要的任何东西。

1
2
3
4
5
$(window).scroll(function(){
   if (isInView($('.classOfDivToCheck')))
      //fire whatever you what
      dothis();
})

对我来说很好


使用("new")IntersectionObserver API

确定元素是否在视区中可见是非常简单和有效的。通过使用观察器,它消除了附加scroll事件和手动检查事件回调的需要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// this is the target which is observed
var target = document.querySelector('div');

// configure the intersection observer instance
var intersectionObserverOptions = {
  root: null,
  rootMargin: '150px',
  threshold: 1.0
}
   
var observer = new IntersectionObserver(onIntersection, intersectionObserverOptions);

// provice the observer with a target
observer.observe(target);

function onIntersection(entries){
  entries.forEach(entry => {
    console.clear();
    console.log(entry.intersectionRatio)
    target.classList.toggle('visible', entry.intersectionRatio > 0);
   
    // Are we in viewport?
    if (entry.intersectionRatio > 0) {
      // Stop watching
      // observer.unobserve(entry.target);
    }
  });
}

1
2
.box{ width:100px; height:100px; background:red; margin:1000px; }
.box.visible{ background:green; }

1
Scroll both Vertically & Horizontally...

查看浏览器支持表(IE/Safari不支持)


WebResourcesDepot在滚动时编写了一个要加载的脚本,该脚本在一段时间前使用了jQuery。你可以在这里观看他们的现场演示。他们的主要功能是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(window).scroll(function(){
  if  ($(window).scrollTop() == $(document).height() - $(window).height()){
    lastAddedLiveFunc();
  }
});

function lastAddedLiveFunc() {
  $('div#lastPostsLoader').html('<img src="images/bigLoader.gif">');
  $.post("default.asp?action=getLastPosts&lastPostID="+$(".wrdLatest:last").attr("id"),
    function(data){
        if (data !="") {
          $(".wrdLatest:last").after(data);        
        }
      $('div#lastPostsLoader').empty();
    });
};


特威克·斯科特·道丁的酷功能满足了我的要求-这用于查找元素是否刚刚滚动到屏幕,即它的上边缘。

1
2
3
4
5
6
7
function isScrolledIntoView(elem)
{
    var docViewTop = $(window).scrollTop();
    var docViewBottom = docViewTop + $(window).height();
    var elemTop = $(elem).offset().top;
    return ((elemTop <= docViewBottom) && (elemTop >= docViewTop));
}


这里的大多数答案都没有考虑到一个元素也可以隐藏,因为它被滚动到一个DIV的视图之外,而不仅仅是整个页面。

为了覆盖这种可能性,您基本上必须检查元素是否位于每个父元素的边界内。

这个解决方案就是这样做的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function(element, percentX, percentY){
    var tolerance = 0.01;   //needed because the rects returned by getBoundingClientRect provide the position up to 10 decimals
    if(percentX == null){
        percentX = 100;
    }
    if(percentY == null){
        percentY = 100;
    }

    var elementRect = element.getBoundingClientRect();
    var parentRects = [];

    while(element.parentElement != null){
        parentRects.push(element.parentElement.getBoundingClientRect());
        element = element.parentElement;
    }

    var visibleInAllParents = parentRects.every(function(parentRect){
        var visiblePixelX = Math.min(elementRect.right, parentRect.right) - Math.max(elementRect.left, parentRect.left);
        var visiblePixelY = Math.min(elementRect.bottom, parentRect.bottom) - Math.max(elementRect.top, parentRect.top);
        var visiblePercentageX = visiblePixelX / elementRect.width * 100;
        var visiblePercentageY = visiblePixelY / elementRect.height * 100;
        return visiblePercentageX + tolerance > percentX && visiblePercentageY + tolerance > percentY;
    });
    return visibleInAllParents;
};

它还允许您指定它在每个方向上的可见百分比。它不包括可能由于其他因素而隐藏的可能性,如display: hidden

这应该适用于所有主要的浏览器,因为它只使用getBoundingClientRect。我在Chrome和Internet Explorer 11中亲自测试过它。


IsScrolledintoView是一个非常需要的功能,所以我尝试了它,它适用于不比视区高的元素,但是如果元素比视区大,它就不工作。要解决这个问题,很容易改变条件

1
return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));

为此:

1
return (docViewBottom >= elemTop && docViewTop <= elemBottom);

参见演示:http://jsfiddle.net/rrsmq/


jquery有一个名为inview的插件,它添加了一个新的"inview"事件。

以下是不使用事件的jquery插件的一些代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$.extend($.expr[':'],{
    inView: function(a) {
        var st = (document.documentElement.scrollTop || document.body.scrollTop),
            ot = $(a).offset().top,
            wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();
        return ot > st && ($(a).height() + ot) < (st + wh);
    }
});

(function( $ ) {
    $.fn.inView = function() {
        var st = (document.documentElement.scrollTop || document.body.scrollTop),
        ot = $(this).offset().top,
        wh = (window.innerHeight && window.innerHeight < $(window).height()) ? window.innerHeight : $(window).height();

        return ot > st && ($(this).height() + ot) < (st + wh);
    };
})( jQuery );

我在一个叫james的家伙的评论(http://remysharp.com/2009/01/26/element-in-view-event-plugin/)中发现了这个。


1
2
3
4
5
6
7
8
function isScrolledIntoView(elem) {
    var docViewTop = $(window).scrollTop(),
        docViewBottom = docViewTop + $(window).height(),
        elemTop = $(elem).offset().top,
     elemBottom = elemTop + $(elem).height();
   //Is more than half of the element visible
   return ((elemTop + ((elemBottom - elemTop)/2)) >= docViewTop && ((elemTop + ((elemBottom - elemTop)/2)) <= docViewBottom));
}


这将考虑元素具有的任何填充、边框或边距,以及大于视区本身的元素。

1
2
3
4
5
6
7
8
9
10
11
function inViewport($ele) {
    var lBound = $(window).scrollTop(),
        uBound = lBound + $(window).height(),
        top = $ele.offset().top,
        bottom = top + $ele.outerHeight(true);

    return (top > lBound && top < uBound)
        || (bottom > lBound && bottom < uBound)
        || (lBound >= top && lBound <= bottom)
        || (uBound >= top && uBound <= bottom);
}

要调用它,请使用类似这样的方法:

1
2
3
4
var $myElement = $('#my-element'),
    canUserSeeIt = inViewport($myElement);

console.log(canUserSeeIt); // true, if element is visible; false otherwise


以下是http://web-profile.com.ua提供的另一个解决方案/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<script type="text/javascript">
$.fn.is_on_screen = function(){
    var win = $(window);
    var viewport = {
        top : win.scrollTop(),
        left : win.scrollLeft()
    };
    viewport.right = viewport.left + win.width();
    viewport.bottom = viewport.top + win.height();

    var bounds = this.offset();
    bounds.right = bounds.left + this.outerWidth();
    bounds.bottom = bounds.top + this.outerHeight();

    return (!(viewport.right < bounds.left || viewport.left > bounds.right ||    viewport.bottom < bounds.top || viewport.top > bounds.bottom));
 };

if( $('.target').length > 0 ) { // if target element exists in DOM
    if( $('.target').is_on_screen() ) { // if target element is visible on screen after DOM loaded
        $('.log').html('target element is visible on screen'); // log info      
    } else {
        $('.log').html('target element is not visible on screen'); // log info
    }
}
$(window).scroll(function(){ // bind window scroll event
if( $('.target').length > 0 ) { // if target element exists in DOM
    if( $('.target').is_on_screen() ) { // if target element is visible on screen after DOM loaded
        $('.log').html('target element is visible on screen'); // log info
    } else {
        $('.log').html('target element is not visible on screen'); // log info
    }
}
});

在jsFiddle中查看


我需要检查可滚动DIV容器中元素的可见性。

1
2
3
4
5
6
7
8
9
10
11
12
    //p = DIV container scrollable
    //e = element
    function visible_in_container(p, e) {
        var z = p.getBoundingClientRect();
        var r = e.getBoundingClientRect();

        // Check style visiblilty and off-limits
        return e.style.opacity > 0 && e.style.display !== 'none' &&
               e.style.visibility !== 'hidden' &&
               !(r.top > z.bottom || r.bottom < z.top ||
                 r.left > z.right || r.right < z.left);
    }


检查元素(el是否在滚动分区(holder中可见)的普通香草色

1
2
3
4
5
6
7
8
9
function isElementVisible (el, holder) {
  holder = holder || document.body
  const { top, bottom, height } = el.getBoundingClientRect()
  const holderRect = holder.getBoundingClientRect()

  return top <= holderRect.top
    ? holderRect.top - top <= height
    : bottom - holderRect.bottom <= height
},

jquery的用法:

1
2
3
var el = $('tr:last').get(0);
var holder = $('table').get(0);
isVisible =  isScrolledIntoView(el, holder);

您可以使用jquery插件"on screen"在滚动时检查元素是否在当前视区中。当选择器出现在屏幕上时,该插件将选择器的":on screen"设置为"真"。这是可以包含在项目中的插件的链接。"http://benickles.github.io/onscreen/jquery.onscreen.min.js"

你可以试试下面的例子,它对我很有用。

1
2
3
4
5
6
7
8
9
10
$(document).scroll(function() {
    if($("#div2").is(':onScreen')) {
        console.log("Element appeared on Screen");
        //do all your stuffs here when element is visible.
    }
    else {
        console.log("Element not on Screen");
        //do all your stuffs here when element is not visible.
    }
});

HTML代码:

1
<hr />

CSS:

1
2
3
4
5
6
#div1 {
    background-color: red;
}
#div2 {
    background-color: green;
}

基于这个伟大的答案,您可以使用ES2015+进一步简化它:

1
2
3
4
function isScrolledIntoView(el) {
  const { top, bottom } = el.getBoundingClientRect()
  return top >= 0 && bottom <= window.innerHeight
}

如果你不关心从窗口出来的顶部,只关心底部已经被看到,这可以简化为

1
2
3
function isSeen(el) {
  return el.getBoundingClientRect().bottom <= window.innerHeight
}

甚至连一条线

1
const isSeen = el => el.getBoundingClientRect().bottom <= window.innerHeight


下面是一种使用moootools(水平、垂直或同时使用两者)实现相同功能的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Element.implement({
inVerticalView: function (full) {
    if (typeOf(full) ==="null") {
        full = true;
    }

    if (this.getStyle('display') === 'none') {
        return false;
    }

    // Window Size and Scroll
    var windowScroll = window.getScroll();
    var windowSize = window.getSize();
    // Element Size and Scroll
    var elementPosition = this.getPosition();
    var elementSize = this.getSize();

    // Calculation Variables
    var docViewTop = windowScroll.y;
    var docViewBottom = docViewTop + windowSize.y;
    var elemTop = elementPosition.y;
    var elemBottom = elemTop + elementSize.y;

    if (full) {
        return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
            && (elemBottom <= docViewBottom) && (elemTop >= docViewTop) );
    } else {
        return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
    }
},
inHorizontalView: function(full) {
    if (typeOf(full) ==="null") {
        full = true;
    }

    if (this.getStyle('display') === 'none') {
        return false;
    }

    // Window Size and Scroll
    var windowScroll = window.getScroll();
    var windowSize = window.getSize();
    // Element Size and Scroll
    var elementPosition = this.getPosition();
    var elementSize = this.getSize();

    // Calculation Variables
    var docViewLeft = windowScroll.x;
    var docViewRight = docViewLeft + windowSize.x;
    var elemLeft = elementPosition.x;
    var elemRight = elemLeft + elementSize.x;

    if (full) {
        return ((elemRight >= docViewLeft) && (elemLeft <= docViewRight)
            && (elemRight <= docViewRight) && (elemLeft >= docViewLeft) );
    } else {
        return ((elemRight <= docViewRight) && (elemLeft >= docViewLeft));
    }
},
inView: function(full) {
    return this.inHorizontalView(full) && this.inVerticalView(full);
}});

我的应用程序中有这样一个方法,但它不使用jquery:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Get the TOP position of a given element. */
function getPositionTop(element){
    var offset = 0;
    while(element) {
        offset += element["offsetTop"];
        element = element.offsetParent;
    }
    return offset;
}

/* Is a given element is visible or not? */
function isElementVisible(eltId) {
    var elt = document.getElementById(eltId);
    if (!elt) {
        // Element not found.
        return false;
    }
    // Get the top and bottom position of the given element.
    var posTop = getPositionTop(elt);
    var posBottom = posTop + elt.offsetHeight;
    // Get the top and bottom position of the *visible* part of the window.
    var visibleTop = document.body.scrollTop;
    var visibleBottom = visibleTop + document.documentElement.offsetHeight;
    return ((posBottom >= visibleTop) && (posTop <= visibleBottom));
}

编辑:此方法适用于(至少版本6)。阅读评论以了解与FF的兼容性。


修改了已接受的答案,以便元素必须将其显示属性设置为"无"以外的其他值,以使质量可见。

1
2
3
4
5
6
7
8
9
10
function isScrolledIntoView(elem) {
   var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();

  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();
  var elemDisplayNotNone = $(elem).css("display") !=="none";

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop) && elemDisplayNotNone);
}


如果您想在另一个DIV中对滚动项进行调整,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function isScrolledIntoView (elem, divID)

{

    var docViewTop = $('#' + divID).scrollTop();


    var docViewBottom = docViewTop + $('#' + divID).height();

    var elemTop = $(elem).offset().top;
    var elemBottom = elemTop + $(elem).height();

    return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}


基于此答案的一个示例,用于检查元素是否75%可见(即少于25%的元素不在屏幕上)。

1
2
3
4
5
6
7
8
9
10
11
function isScrolledIntoView(el) {
  // check for 75% visible
  var percentVisible = 0.75;
  var elemTop = el.getBoundingClientRect().top;
  var elemBottom = el.getBoundingClientRect().bottom;
  var elemHeight = el.getBoundingClientRect().height;
  var overhang = elemHeight * (1 - percentVisible);

  var isVisible = (elemTop >= -overhang) && (elemBottom <= window.innerHeight + overhang);
  return isVisible;
}


可滚动DIV(容器)的简单修改

1
2
3
4
5
6
var isScrolledIntoView = function(elem, container) {
    var containerHeight = $(container).height();
    var elemTop = $(elem).position().top;
    var elemBottom = elemTop + $(elem).height();
    return (elemBottom > 0 && elemTop < containerHeight);
}

注意:如果元素大于滚动分区,则此操作不起作用。


我修改了这个简短的jquery函数扩展,您可以随意使用(MIT许可证)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * returns true if an element is visible, with decent performance
 * @param [scope] scope of the render-window instance; default: window
 * @returns {boolean}
 */

jQuery.fn.isOnScreen = function(scope){
    var element = this;
    if(!element){
        return;
    }
    var target = $(element);
    if(target.is(':visible') == false){
        return false;
    }
    scope = $(scope || window);
    var top = scope.scrollTop();
    var bot = top + scope.height();
    var elTop = target.offset().top;
    var elBot = elTop + target.height();

    return ((elBot <= bot) && (elTop >= top));
};

我更喜欢使用jquery expr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
jQuery.extend(jQuery.expr[':'], {  
    inview: function (elem) {
        var t = $(elem);
        var offset = t.offset();
        var win = $(window);
        var winST = win.scrollTop();
        var elHeight = t.outerHeight(true);

        if ( offset.top > winST - elHeight && offset.top < winST + elHeight + win.height()) {
            return true;    
        }    
        return false;  
    }
});

所以你可以这样用

1
2
3
$(".my-elem:inview"); //returns only element that is in view
$(".my-elem").is(":inview"); //check if element is in view
$(".my-elem:inview").length; //check how many elements are in view

您可以轻松地在scroll事件函数等中添加此类代码,以便在每次用户滚动视图时检查它。


我已经为这个任务编写了一个组件,它可以非常快速地处理大量元素(对于速度较慢的移动设备上的1000个元素,调到小于10毫秒)。

它适用于您可以访问的每种类型的滚动容器——窗口、HTML元素、嵌入的iframe、生成的子窗口——并且在检测到的内容方面非常灵活(完全或部分可见性、边框或内容框、自定义公差带等)。

一个巨大的,主要是自动生成的测试套件可以确保它像广告中那样跨浏览器工作。

如果您愿意,可以试一试:jquery.isinview。否则,您可能会在源代码中找到灵感,例如这里。


我在寻找一种方法来查看元素是否很快就会出现,所以通过扩展上面的代码片段,我成功地做到了这一点。我想我会把这个留在这里,以防它能帮助别人。

elm=要检查的元素是否在视图中

ScrollElement=可以传递窗口或具有滚动的父元素

offset=如果希望在元素在屏幕中出现之前在200px之外时激发它,则通过200

1
2
3
4
5
6
7
8
9
10
11
function isScrolledIntoView(elem, scrollElement, offset)
        {
            var $elem = $(elem);
            var $window = $(scrollElement);
            var docViewTop = $window.scrollTop();
            var docViewBottom = docViewTop + $window.height();
            var elemTop = $elem.offset().top;
            var elemBottom = elemTop + $elem.height();
           
            return (((elemBottom+offset) >= docViewBottom) && ((elemTop-offset) <= docViewTop)) || (((elemBottom-offset) <= docViewBottom) && ((elemTop+offset) >= docViewTop));
        }


这个问题有30多个答案,没有一个使用我一直使用的非常简单的纯JS解决方案。没有必要仅仅为了解决这个问题而加载jquery,因为许多其他人正在推送它。

为了判断元素是否在视区中,我们必须首先确定元素在主体中的位置。我们不需要像我曾经想的那样递归地做这个。相反,我们可以使用element.getBoundingClientRect()

1
pos = elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top;

该值是对象顶部和主体顶部之间的Y差。

然后我们必须判断元素是否在视图中。大多数实现都会询问整个元素是否在视区内,所以这就是我们要讨论的内容。

首先,窗口的顶部位置是:window.scrollY

我们可以通过将窗口的高度添加到其顶部位置来获取窗口的底部位置:

1
var window_bottom_position = window.scrollY + window.innerHeight;

让我们创建一个简单的函数来获取元素的顶部位置:

1
2
3
function getElementWindowTop(elem){
    return elem && typeof elem.getBoundingClientRect === 'function' ? elem.getBoundingClientRect().top - document.body.getBoundingClientRect().top : 0;
}

此函数将返回元素在窗口中的顶部位置,或者如果使用.getBoundingClientRect()方法传递元素以外的其他元素,它将返回0。这种方法已经存在很长时间了,所以您不必担心浏览器不支持它。

现在,元素的首要位置是:

1
var element_top_position = getElementWindowTop(element);

和或元素的底部位置是:

1
var element_bottom_position = element_top_position + element.clientHeight;

现在,我们可以通过检查元素的底部位置是否低于视区的顶部位置以及检查元素的顶部位置是否高于视区的底部位置来确定元素是否在视区内:

1
2
3
4
5
if(element_bottom_position >= window.scrollY
&& element_top_position <= window_bottom_position){
    //element is in view
else
    //element is not in view

从那里,您可以执行逻辑来添加或删除元素上的in-view类,然后您可以在CSS中使用转换效果处理该类。

我很惊讶我在任何地方都没有找到这个解决方案,但是我相信这是最干净和最有效的解决方案,并且不需要您加载jquery!


如果元素的任何部分在页面上可见,则此方法将返回true。在我的情况下效果更好,可能会帮助其他人。

1
2
3
4
5
6
7
8
9
10
11
12
function isOnScreen(element) {
  var elementOffsetTop = element.offset().top;
  var elementHeight = element.height();

  var screenScrollTop = $(window).scrollTop();
  var screenHeight = $(window).height();

  var scrollIsAboveElement = elementOffsetTop + elementHeight - screenScrollTop >= 0;
  var elementIsVisibleOnScreen = screenScrollTop + screenHeight - elementOffsetTop >= 0;

  return scrollIsAboveElement && elementIsVisibleOnScreen;
}


我只是想分享一下,我把这个和我的脚本结合起来,移动这个DIV,使它始终保持在视图中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    $("#accordion").on('click', '.subLink', function(){
        var url = $(this).attr('src');
        updateFrame(url);
        scrollIntoView();
    });

    $(window).scroll(function(){
            changePos();
    });

  function scrollIntoView()
  {
        var docViewTop = $(window).scrollTop();
        var docViewBottom = docViewTop + $(window).height();    
        var elemTop = $("#divPos").offset().top;
        var elemBottom = elemTop + $("#divPos").height();              
        if (elemTop < docViewTop){
            $("#divPos").offset({top:docViewTop});
        }
   }

   function changePos(){        
    var scrTop = $(window).scrollTop();
    var frmHeight = $("#divPos").height()
        if ((scrTop < 200) || (frmHeight > 800)){  
         $("#divPos").attr("style","position:absolute;");
        }else{
          $("#divPos").attr("style","position:fixed;top:5px;");
        }
    }

此答案的更有效版本:

1
2
3
4
5
6
7
8
9
 /**
 * Is element within visible region of a scrollable container
 * @param {HTMLElement} el - element to test
 * @returns {boolean} true if within visible region, otherwise false
 */

 function isScrolledIntoView(el) {
      var rect = el.getBoundingClientRect();
      return (rect.top >= 0) && (rect.bottom <= window.innerHeight);
 }


在使用ES6的现代浏览器中,我们可以这样做:

1
2
3
4
5
6
const isFullySeen = el => el &&
  typeof el.getBoundingClientRect === 'function' &&
  el.getBoundingClientRect()['bottom'] + window.scrollY <=
    window.innerHeight + window.scrollY &&
  el.getBoundingClientRect()['top'] + window.scrollY <=
    window.innerHeight + window.scrollY;


唯一对我来说一直有效的插件是:https://github.com/customd/jquery-visible

我最近把这个插件移植到了GWT,因为我不想仅仅为了使用插件而将jquery作为依赖项添加。这是我的(简单)端口(仅包括我的用例所需的功能):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static boolean isVisible(Element e)
{
    //vp = viewPort, b = bottom, l = left, t = top, r = right
    int vpWidth   = Window.getClientWidth();
    int vpHeight = Window.getClientHeight();


    boolean tViz = ( e.getAbsoluteTop() >= 0 && e.getAbsoluteTop()<  vpHeight);
    boolean bViz = (e.getAbsoluteBottom() >  0 && e.getAbsoluteBottom() <= vpHeight);
    boolean lViz = (e.getAbsoluteLeft() >= 0 && e.getAbsoluteLeft() < vpWidth);
    boolean rViz = (e.getAbsoluteRight()  >  0 && e.getAbsoluteRight()  <= vpWidth);

    boolean vVisible   = tViz && bViz;
    boolean hVisible   = lViz && rViz;

    return hVisible && vVisible;
}

检查元素是否在屏幕上,而不是检查DIV是否完全在屏幕上的公认答案方法(如果DIV大于屏幕,则不起作用)。在纯JavaScript中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
 * Checks if element is on the screen (Y axis only), returning true
 * even if the element is only partially on screen.
 *
 * @param element
 * @returns {boolean}
 */

function isOnScreenY(element) {
    var screen_top_position = window.scrollY;
    var screen_bottom_position = screen_top_position + window.innerHeight;

    var element_top_position = element.offsetTop;
    var element_bottom_position = element_top_position + element.offsetHeight;

    return (inRange(element_top_position, screen_top_position, screen_bottom_position)
    || inRange(element_bottom_position, screen_top_position, screen_bottom_position));
}

/**
 * Checks if x is in range (in-between) the
 * value of a and b (in that order). Also returns true
 * if equal to either value.
 *
 * @param x
 * @param a
 * @param b
 * @returns {boolean}
 */

function inRange(x, a, b) {
    return (x >= a && x <= b);
}


制作了一个简单的插件,用于检测元素是否在可滚动容器中可见。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    $.fn.isVisible = function(){

      var win;
      if(!arguments[0])
      {
        console.error('Specify a target;');
        return false;
      }
      else
      {
        win = $(arguments[0]);
      }
      var viewport = {};
      var bounds = this.offset();
      bounds.right = bounds.left + this.outerWidth();
      bounds.bottom = bounds.top + this.outerHeight();
      viewport.bottom = win.height() + win.offset().top;
      return (!( bounds.top > viewport.bottom) && (win.offset().top < bounds.bottom));
    };

像这样叫它$('elem_to_check').isVisible('scrollable_container');

希望能有所帮助。


仅限javascript:)

1
2
3
4
5
6
7
8
9
10
function isInViewport(element) {
  var rect = element.getBoundingClientRect();
  var html = document.documentElement;
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || html.clientHeight) &&
    rect.right <= (window.innerWidth || html.clientWidth)
  );
}


在运行了一些没有效果的代码之后。这就是我使用jquery在垂直滚动可见性上的工作原理。将"footerplace"替换为要垂直跟踪的元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
jQuery.expr.filters.offscreen = function(el) {
  var rect = el.getBoundingClientRect();
  console.log(rect)
  console.log('window height', $(window).height());

  return (
           (rect.top <= $(window).height()) && (rect.bottom <= $(window).height())
         );
};
$(document).scroll(function(){
    if ($('#footerplace').is(':offscreen')){
      console.log('this is true');
    $('#footerplace').is(':offscreen');
    } else {
     console.log('this is false');
    $('#footerplace').is(':offscreen');

    }