Scroll if element is not visible

2019-01-23 13:09发布

问题:

how to determine, using jquery, if the element is visible on the current page view. I'd like to add a comment functionality, which works like in facebook, where you only scroll to element if it's not currently visible. By visible, I mean that it is not in the current page view, but you can scroll to the element.

回答1:

Live Demo

Basically you just check the position of the element to see if its within the windows viewport.

function checkIfInView(element){
    var offset = element.offset().top - $(window).scrollTop();

    if(offset > window.innerHeight){
        // Not in view so scroll to it
        $('html,body').animate({scrollTop: offset}, 1000);
        return false;
    }
   return true;
}


回答2:

Improving Loktar's answer, fixing the following:

  1. Scroll up
  2. Scroll to a display:none element (like hidden div's etc)

    function scrollToView(element){
        var offset = element.offset().top;
        if(!element.is(":visible")) {
            element.css({"visibility":"hidden"}).show();
            var offset = element.offset().top;
            element.css({"visibility":"", "display":""});
        }
    
        var visible_area_start = $(window).scrollTop();
        var visible_area_end = visible_area_start + window.innerHeight;
    
        if(offset < visible_area_start || offset > visible_area_end){
             // Not in view so scroll to it
             $('html,body').animate({scrollTop: offset - window.innerHeight/3}, 1000);
             return false;
        }
        return true;
    }
    


回答3:

After trying all these solutions and many more besides, none of them satisfied my requirement for running old web portal software (10 years old) inside IE11 (in some compatibility mode). They all failed to correctly determine if the element was visible. However I found this solution. I hope it helps.

function scrollIntoViewIfOutOfView(el) {
    var topOfPage = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
    var heightOfPage = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    var elY = 0;
    var elH = 0;
    if (document.layers) { // NS4
        elY = el.y;
        elH = el.height;
    }
    else {
        for(var p=el; p&&p.tagName!='BODY'; p=p.offsetParent){
            elY += p.offsetTop;
        }
        elH = el.offsetHeight;
    }
    if ((topOfPage + heightOfPage) < (elY + elH)) {
        el.scrollIntoView(false);
    }
    else if (elY < topOfPage) {
        el.scrollIntoView(true);
    }
}


回答4:

I made a slightly more generic version of digitalPBK's answer that minimally scrolls an element contained within a div or some other container (including the body). You can pass DOM elements or selectors to the function, as long as the element is somehow contained within the parent.

function scrollToView(element, parent) {
    element = $(element);
    parent = $(parent);

    var offset = element.offset().top + parent.scrollTop();

    var height = element.innerHeight();
    var offset_end = offset + height;
    if (!element.is(":visible")) {
        element.css({"visibility":"hidden"}).show();
        var offset = element.offset().top;
        element.css({"visibility":"", "display":""});
    }

    var visible_area_start = parent.scrollTop();
    var visible_area_end = visible_area_start + parent.innerHeight();

    if (offset-height < visible_area_start) {
        parent.animate({scrollTop: offset-height}, 600);
        return false;
    } else if (offset_end > visible_area_end) {
        parent.animate({scrollTop: parent.scrollTop()+ offset_end - visible_area_end }, 600);
        return false;

    }
    return true;
}


回答5:

You can take a look at his awesome link from the jQuery Cookbook:

Determining Whether an Element Is Within the Viewport

Test if Element is contained in the Viewport

jQuery(document).ready(function() {
    var viewportWidth = jQuery(window).width(),
        viewportHeight = jQuery(window).height(),
        documentScrollTop = jQuery(document).scrollTop(),
        documentScrollLeft = jQuery(document).scrollLeft(),

        $myElement = jQuery('#myElement'),

        elementOffset = $myElement.offset(),
        elementHeight = $myElement.height(),
        elementWidth = $myElement.width(),

        minTop = documentScrollTop,
        maxTop = documentScrollTop + viewportHeight,
        minLeft = documentScrollLeft,
        maxLeft = documentScrollLeft + viewportWidth;

    if (
        (elementOffset.top > minTop && elementOffset.top + elementHeight < maxTop) &&
        (elementOffset.left > minLeft && elementOffset.left + elementWidth < maxLeft)
    ) {
        alert('entire element is visible');
    } else {
        alert('entire element is not visible');
    }
});

Test how much of the element is visible

jQuery(document).ready(function() {

var viewportWidth = jQuery(window).width(),
    viewportHeight = jQuery(window).height(),

    documentScrollTop = jQuery(document).scrollTop(),
    documentScrollLeft = jQuery(document).scrollLeft(),

    $myElement = jQuery('#myElement'),

    verticalVisible, horizontalVisible,

    elementOffset = $myElement.offset(),
    elementHeight = $myElement.height(),
    elementWidth = $myElement.width(),

    minTop = documentScrollTop,
    maxTop = documentScrollTop + viewportHeight,
    minLeft = documentScrollLeft,
    maxLeft = documentScrollLeft + viewportWidth;

function scrollToPosition(position) {
    jQuery('html,body').animate({
        scrollTop : position.top,
        scrollLeft : position.left
    }, 300);
}

if (
    ((elementOffset.top > minTop && elementOffset.top < maxTop) ||
    (elementOffset.top + elementHeight > minTop && elementOffset.top + 
elementHeight < maxTop))
&&  ((elementOffset.left > minLeft && elementOffset.left < maxLeft) ||
    (elementOffset.left + elementWidth > minLeft && elementOffset.left +
elementWidth < maxLeft)))
{
    alert('some portion of the element is visible');

    if (elementOffset.top >= minTop && elementOffset.top + elementHeight 
<= maxTop) {
        verticalVisible = elementHeight;
    } else if (elementOffset.top < minTop) {
        verticalVisible = elementHeight - (minTop - elementOffset.top);
    } else {
        verticalVisible = maxTop - elementOffset.top;
    }

    if (elementOffset.left >= minLeft && elementOffset.left + elementWidth 
<= maxLeft) {
        horizontalVisible = elementWidth;
    } else if (elementOffset.left < minLeft) {
        horizontalVisible = elementWidth - (minLeft - elementOffset.left);
    } else {
        horizontalVisible = maxLeft - elementOffset.left;
    }

    var percentVerticalVisible = (verticalVisible / elementHeight) * 100;
    var percentHorizontalVisible = (horizontalVisible / elementWidth) * 100;

    if (percentVerticalVisible < 50 || percentHorizontalVisible < 50) {
        alert('less than 50% of element visible; scrolling');
        scrollToPosition(elementOffset);
    } else {
        alert('enough of the element is visible that there is no need to scroll');
    }

} else {
    // element is not visible; scroll to it
    alert('element is not visible; scrolling');
    scrollToPosition(elementOffset);
}


回答6:

The following code helped me achieve the result

function scroll_to_element_if_not_inside_view(element){
  if($(window).scrollTop() > element.offset().top){
    $('html, body').animate( { scrollTop: element.offset().top }, {duration: 400 } );
  }
}


回答7:

There is a jQuery plugin which allows us to quickly check if a whole element (or also only part of it) is within the browsers visual viewport regardless of the window scroll position. You need to download it from its GitHub repository:

Suppose to have the following HTML and you want to alert when footer is visible:

<section id="container">
    <aside id="sidebar">
        <p>
            Scroll up and down to alert the footer visibility by color:
        </p>
        <ul>
            <li><span class="blue">Blue</span> = footer <u>not visible</u>;</li>
            <li><span class="yellow">Yellow</span> = footer <u>visible</u>;</li>
        </ul>
        <span id="alert"></span>
    </aside>
    <section id="main_content"></section>
</section>
<footer id="page_footer"></footer>

So, add the plugin before the close of body tag:

<script type="text/javascript" src="js/jquery-1.12.0.min.js"></script>
<script type="text/javascript" src="js/jquery_visible/examples/js/jq.visible.js"></script>

After that you can use it in a simple way like this:

<script type="text/javascript">
jQuery( document ).ready(function ( $ ) {
  if ($("footer#page_footer").visible(true, false, "both")) {
    $("#main_content").css({"background-color":"#ffeb3b"});
    $("span#alert").html("Footer visible");
  } else {
    $("#main_content").css({"background-color":"#4aafba"});
    $("span#alert").html("Footer not visible");
  }

  $(window).scroll(function() {
    if ($("footer#page_footer").visible(true, false, "both")) {
      $("#main_content").css({"background-color":"#ffeb3b"});
      $("span#alert").html("Footer visible");
    } else {
      $("#main_content").css({"background-color":"#4aafba"});
      $("span#alert").html("Footer not visible");
    }
  });
});
</script>

Here a demo