JacobTheDev
JacobTheDev

Reputation: 18520

Get the visible height of a div with jQuery

I need to retrieve the visible height of a div within a scrollable area. I consider myself pretty decent with jQuery, but this is completely throwing me off.

Let's say I've got a red div within a black wrapper:

In the graphic above, the jQuery function would return 248, the visible portion of the div.

Once the user scrolls past the top of the div, as in the above graphic, it would report 296.

Now, once the user has scrolled past the div, it would again report 248.

Obviously my numbers aren't going to be as consistent and clear as they are in this demo, or I'd just hard code for those numbers.

I have a bit of a theory:

It seems pretty simple, but I just can't wrap my head around it. I'll take another crack tomorrow morning; I just figured some of you geniuses might be able to help.

Thanks!

UPDATE: I figured this out on my own, but looks like one of the answers below is more elegant, so I'll be using that instead. For the curious, here's what I came up with:

$(document).ready(function() {
    var windowHeight = $(window).height();
    var overviewHeight = $("#overview").height();
    var overviewStaticTop = $("#overview").offset().top;
    var overviewScrollTop = overviewStaticTop - $(window).scrollTop();
    var overviewStaticBottom = overviewStaticTop + $("#overview").height();
    var overviewScrollBottom = windowHeight - (overviewStaticBottom - $(window).scrollTop());
    var visibleArea;
    if ((overviewHeight + overviewScrollTop) < windowHeight) {
        // alert("bottom is showing!");
        visibleArea = windowHeight - overviewScrollBottom;
        // alert(visibleArea);
    } else {
        if (overviewScrollTop < 0) {
            // alert("is full height");
            visibleArea = windowHeight;
            // alert(visibleArea);
        } else {
            // alert("top is showing");
            visibleArea = windowHeight - overviewScrollTop;
            // alert(visibleArea);
        }
    }
});

Upvotes: 95

Views: 77646

Answers (4)

hitesh patel
hitesh patel

Reputation: 1

Here is the improved code for jquery function visibleHeight: $("#myDiv").visibleHeight();

$.fn.visibleHeight = function() {
    var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop, height;
    scrollTop = $(window).scrollTop();
    scrollBot = scrollTop + $(window).height();
    elTop = this.offset().top;
    elBottom = elTop + this.outerHeight();
    visibleTop = elTop < scrollTop ? scrollTop : elTop;
    visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
    height = visibleBottom - visibleTop;
    return height > 0 ? height : 0;
}

Upvotes: 0

Rory McCrossan
Rory McCrossan

Reputation: 337560

Here is a quick and dirty concept. It basically compares the offset().top of the element to the top of the window, and the offset().top + height() to the bottom of the window:

function getVisible() {
  var $el = $('#foo'),
    scrollTop = $(this).scrollTop(),
    scrollBot = scrollTop + $(this).height(),
    elTop = $el.offset().top,
    elBottom = elTop + $el.outerHeight(),
    visibleTop = elTop < scrollTop ? scrollTop : elTop,
    visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
  $('#notification').text(`Visible height of div: ${visibleBottom - visibleTop}px`);
}

$(window).on('scroll resize', getVisible).trigger('scroll');
html,
body {
  margin: 100px 0;
}

#foo {
  height: 1000px;
  background-color: #C00;
  width: 200px;
  margin: 0 auto;
}

#notification {
  position: fixed;
  top: 0;
  left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="foo"></div>
<div id="notification"></div>

The logic can be made more succinct if necessary, I've just declared separate variables for this example to make the calculation as clear as I can.

Upvotes: 61

Roko C. Buljan
Roko C. Buljan

Reputation: 206008

Calculate the amount of px an element (height) is in viewport

Fiddle demo

This tiny function will return the amount of px an element is visible in the (vertical) Viewport:

function inViewport($el) {
    var elH = $el.outerHeight(),
        H   = $(window).height(),
        r   = $el[0].getBoundingClientRect(), t=r.top, b=r.bottom;
    return Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H));
}

Use like:

$(window).on("scroll resize", function(){
  console.log( inViewport($('#elementID')) ); // n px in viewport
});

that's it.


jQuery .inViewport() Plugin

jsFiddle demo

from the above you can extract the logic and create a plugin like this one:

/**
 * inViewport jQuery plugin by Roko C.B.
 * http://stackoverflow.com/a/26831113/383904
 * Returns a callback function with an argument holding
 * the current amount of px an element is visible in viewport
 * (The min returned value is 0 (element outside of viewport)
 */
;(function($, win) {
  $.fn.inViewport = function(cb) {
     return this.each(function(i,el) {
       function visPx(){
         var elH = $(el).outerHeight(),
             H = $(win).height(),
             r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
         return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));  
       }
       visPx();
       $(win).on("resize scroll", visPx);
     });
  };
}(jQuery, window));

Use like:

$("selector").inViewport(function(px) {
  console.log( px ); // `px` represents the amount of visible height
  if(px > 0) {
    // do this if element enters the viewport // px > 0
  }else{
    // do that if element exits  the viewport // px = 0
  }
}); // Here you can chain other jQuery methods to your selector

your selectors will dynamically listen to window scroll and resize but also return the initial value on DOM ready trough the first callback function argument px.

Upvotes: 67

Michael.Lumley
Michael.Lumley

Reputation: 2385

Here is a version of Rory's approach above, except written to function as a jQuery plugin. It may have more general applicability in that format. Great answer, Rory - thanks!

$.fn.visibleHeight = function() {
    var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop;
    scrollTop = $(window).scrollTop();
    scrollBot = scrollTop + $(window).height();
    elTop = this.offset().top;
    elBottom = elTop + this.outerHeight();
    visibleTop = elTop < scrollTop ? scrollTop : elTop;
    visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
    return visibleBottom - visibleTop
}

Can be called with the following:

$("#myDiv").visibleHeight();

jsFiddle

Upvotes: 12

Related Questions