Obtenir la hauteur de la partie non débordée de div

Dites que j'ai une enveloppe div avec un overflow:hidden sur elle et un div à l'intérieur qui s'étend très au-dessous de la partie visible. Comment puis-je obtenir la hauteur visible de la div interne?

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

Chaque méthode que j'essaie d'essayer d'obtenir la hauteur du div interne renvoie la hauteur complète, y compris les parties cachées, c'est-à-dire 2000px. Je veux pouvoir obtenir la hauteur de seulement la partie visible, donc 400px dans cet exemple.

Je sais que je pourrais juste avoir la hauteur de parentNode , mais en production, le div intérieur pourrait ne pas être un premier enfant. Donc, il pourrait y avoir d'autres divs qui les séparent, et donc la hauteur de #inner serait de 400 – quels que soient les décalages des éléments entre lui et #wrapper .

Comme algorithme de base, cela pourrait fonctionner:

 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; 

Mais si vous faites ce genre de choses, peut-être que vous utilisez déjà jQuery, qui pourrait être utile avec ses fonctions .height() et .offset() :

 $("#wrapper").height()- $("#inner").offset()['top']+ $("#wrapper").offset()['top']; 

Algorithme rapide qui monte l'arborescence DOM en regardant window.getComputedStyle pour 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 - dy; // calculate visible y x = node.offsetWidth - dx; // 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 dy = dy + (node.offsetTop || 0); dx = dx + (node.offsetLeft || 0); d.node = node.offsetParent; } } return o; // return if no hidden } 

Exemple de violon (regardez votre console).

La seule façon que j'ai trouvée de le faire dans toutes les circonstances, y compris quand il y a un débordement, transform: translate() s sont utilisés et il existe d'autres conteneurs imbriqués entre un élément et l'élément qui cache son débordement est de combiner .getBoundingClientRect() Avec une référence à l'ancêtre qui cache le débordement de l'élément:

 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) ) } } 

Démonstration .

Si un noeud de référence n'est pas donné, le noeud parent est supposé: démo .

Notez que cela ne tient pas compte du fait qu'un élément soit ou non visible dans la fenêtre , juste visible (non caché en raison du débordement). Si vous avez besoin des deux, vous pouvez combiner les fonctionnalités avec cette réponse . Il n'a pas non plus de visibility: hidden , donc, si vous avez besoin, vous devez vérifier la propriété style.visibility du nœud et de tous ses ancêtres.

Je pense que garder un frerre à côté de lui, calculer son scrollTop et l'élément de débordement scrollTop et le soustraire des frères et sœurs scroolTop pourrait fonctionner

Le code ci-dessous calcule la partie visible d'un élément. Par partie visible, je veux dire la partie visible dans la fenêtre , mais je pense que vous pouvez facilement la modifier pour baser le calcul sur un élément de conteneur arbitraire.

 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); } } 

Le code utilise jquery.