12

Say I have a wrapper div with a overflow:hidden on it and a div inside that that spans far below the visible portion. How can I get the visible height of the internal div?

<div id="wrapper" style="overflow: hidden; height:400px;">
    <div id="inner">
        <!--Lots of content in here-->
    </div>
<div>

Every method I try attempting to get the height of the inner div returns the complete height including the hidden parts, i.e. 2000px. I want to be able to get the height of only the visible portion, so 400px in this example case.

I know I could just get the height of the parentNode, but in production, the inner div might not be a first child. So there might be other divs separating them, and so the height of #inner would be 400 - whatever the offsets of the elements between it and #wrapper.

Zach Saucier
  • 24,871
  • 12
  • 85
  • 147
ryandlf
  • 27,155
  • 37
  • 106
  • 162
  • Ya...i'm thinking I could traverse the dom up until I find an overflow hidden tag. But others might also have this...I dunno. Gotta rack my brain unless others come up with a solution. – ryandlf Oct 12 '12 at 23:24

5 Answers5

7

As basic algorithm this could work:

var offset = 0;
var node = document.getElementById("inner");
while (node.offsetParent && node.offsetParent.id != "wrapper")
{
    offset += node.offsetTop;
    node = node.offsetParent;
}
var visible = node.offsetHeight - offset;

But if you're doing these kinds of things, maybe you already use jQuery, which might be of service with its .height() and .offset() functions:

$("#wrapper").height()-
$("#inner").offset()['top']+
$("#wrapper").offset()['top'];  
Zach Saucier
  • 24,871
  • 12
  • 85
  • 147
Wolfgang Stengel
  • 2,867
  • 1
  • 17
  • 22
3

Quick algorithm that goes up the DOM tree looking at window.getComputedStyle for overflow: hidden

function visibleArea(node){
    var o = {height: node.offsetHeight, width: node.offsetWidth}, // size
        d = {y: (node.offsetTop || 0), x: (node.offsetLeft || 0), node: node.offsetParent}, // position
        css, y, x;
    while( null !== (node = node.parentNode) ){  // loop up through DOM
        css = window.getComputedStyle(node);
        if( css && css.overflow === 'hidden' ){  // if has style && overflow
            y = node.offsetHeight - d.y;         // calculate visible y
            x = node.offsetWidth - d.x;          // and x
            if( node !== d.node ){
                y = y + (node.offsetTop || 0);   // using || 0 in case it doesn't have an offsetParent
                x = x + (node.offsetLeft || 0);
            }
            if( y < o.height ) {
                if( y < 0 ) o.height = 0;
                else o.height = y;
            }
            if( x < o.width ) {
                if( x < 0 ) o.width = 0;
                else o.width = x;
            }
            return o;                            // return (modify if you want to loop up again)
        }
        if( node === d.node ){                   // update offsets
            d.y = d.y + (node.offsetTop || 0);
            d.x = d.x + (node.offsetLeft || 0);
            d.node = node.offsetParent;
        }
    }
    return o;                                    // return if no hidden
}

example fiddle (look at your console).

Paul S.
  • 64,864
  • 9
  • 122
  • 138
1

The only way I've found to do this in every circumstance, including when there's overflow, transform: translate()s are used, and there are other nested containers in between an element and the element that's hiding its overflow is to combine .getBoundingClientRect() with a reference to the ancestor that's hiding the element's overflow:

function getVisibleDimensions(node, referenceNode) {
    referenceNode = referenceNode || node.parentNode;

    var pos = node.getBoundingClientRect();
    var referencePos = referenceNode.getBoundingClientRect();

    return {
        "width": Math.min(
            node.clientWidth,
            referencePos.left + referenceNode.clientWidth - pos.left, 
            node.clientWidth - (referencePos.left - pos.left)
        ),
        "height": Math.min(
            node.clientHeight, 
            referencePos.top + referenceNode.clientHeight - pos.top,
            node.clientHeight - (referencePos.top - pos.top)
        )
    }
}

Demo.

If a reference node is not given, the parent node is assumed: Demo.

Note that this doesn't take into account whether or not an element is viewable in the viewport, just visible (not hidden due to overflow). If you need both, you can combine functionality with this answer. It also has no check of visibility: hidden, so if you need that you need to check the style.visibility property of the node and all its ancestors.

Zach Saucier
  • 24,871
  • 12
  • 85
  • 147
-1

I think keeping a sibling next to it, calculating its scrollTop and the overflow element scrollTop and then subtracting it from the siblings scroolTop might work

Amareswar
  • 2,048
  • 1
  • 20
  • 36
-1

The code below computes the visible portion of an element. By visible portion I mean the part that is visible in the window, but I think you can easily alter it to base the computation on an arbitrary container element.

function computeVisibleHeight ($t) {
        var top = $t.position().top;
        var windowHeight = $(window).height();
        var scrollTop = $(window).scrollTop();
        var height = $t.height();

        if (top < scrollTop && height - scrollTop >= windowHeight) {
            // first case: the top and the bottom of the element is outside of the window
            return windowHeight;
        } else if (top < scrollTop) {
            // second: the top is outside of the viewport but the bottom is visible
            return height - (scrollTop - top);
        } else if (top > scrollTop && top + height < windowHeight) {
            // the whole element is visible
            return height;
        } else {
            // the top is visible but the bottom is outside of the viewport
            return windowHeight - (top - scrollTop);
        }
    }

The code is using jquery.

akostajti
  • 2,997
  • 1
  • 14
  • 6