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
.
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
.
- 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 Commented Oct 12, 2012 at 23:24
5 Answers
Reset to default 7As 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'];
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).
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.
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
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.