Então esta é a resposta?
"Se você precisar calcular algo, mas não mostrar, defina o elemento como visibility:hidden
e position:absolute
adicione-o à árvore DOM, obtenha o offsetHeight e remova-o. (É o que a biblioteca de protótipos faz atrás das linhas da última vez que verifiquei)."
Eu tenho o mesmo problema em vários elementos. Não há jQuery ou Prototype para ser usado no site, mas sou a favor de pedir emprestada a técnica, se funcionar. Como exemplo de algumas coisas que não funcionaram, seguidas pelo que aconteceu, tenho o seguinte código:
// Layout Height Get
function fnElementHeightMaxGet(DoScroll, DoBase, elementPassed, elementHeightDefault)
{
var DoOffset = true;
if (!elementPassed) { return 0; }
if (!elementPassed.style) { return 0; }
var thisHeight = 0;
var heightBase = parseInt(elementPassed.style.height);
var heightOffset = parseInt(elementPassed.offsetHeight);
var heightScroll = parseInt(elementPassed.scrollHeight);
var heightClient = parseInt(elementPassed.clientHeight);
var heightNode = 0;
var heightRects = 0;
//
if (DoBase) {
if (heightBase > thisHeight) { thisHeight = heightBase; }
}
if (DoOffset) {
if (heightOffset > thisHeight) { thisHeight = heightOffset; }
}
if (DoScroll) {
if (heightScroll > thisHeight) { thisHeight = heightScroll; }
}
//
if (thisHeight == 0) { thisHeight = heightClient; }
//
if (thisHeight == 0) {
// Dom Add:
// all else failed so use the protype approach...
var elBodyTempContainer = document.getElementById('BodyTempContainer');
elBodyTempContainer.appendChild(elementPassed);
heightNode = elBodyTempContainer.childNodes[0].offsetHeight;
elBodyTempContainer.removeChild(elementPassed);
if (heightNode > thisHeight) { thisHeight = heightNode; }
//
// Bounding Rect:
// Or this approach...
var clientRects = elementPassed.getClientRects();
heightRects = clientRects.height;
if (heightRects > thisHeight) { thisHeight = heightRects; }
}
//
// Default height not appropriate here
// if (thisHeight == 0) { thisHeight = elementHeightDefault; }
if (thisHeight > 3000) {
// ERROR
thisHeight = 3000;
}
return thisHeight;
}
que basicamente tenta de tudo para obter um resultado zero. ClientHeight sem efeito. Com os elementos problemáticos, normalmente recebo NaN na Base e zero nas alturas Offset e Scroll. Tentei a solução Add DOM e o clientRects para ver se funciona aqui.
Em 29 de junho de 2011, atualizei o código para tentar adicionar ao DOM e ao clientHeight com melhores resultados do que eu esperava.
1) clientHeight também foi 0.
2) Dom realmente me deu uma altura que foi ótima.
3) ClientRects retorna um resultado quase idêntico à técnica DOM.
Como os elementos adicionados são fluidos por natureza, quando são adicionados a um elemento DOM Temp vazio, eles são renderizados de acordo com a largura desse contêiner. Isso fica estranho, porque é 30px mais curto do que acaba.
Adicionei alguns instantâneos para ilustrar como a altura é calculada de maneira diferente.
As diferenças de altura são óbvias. Eu certamente poderia adicionar posicionamento absoluto e oculto, mas tenho certeza de que isso não terá efeito. Continuei convencido de que isso não funcionaria!
(Discordo mais) A altura sai (é renderizada) menor que a verdadeira altura renderizada. Isso poderia ser resolvido configurando a largura do elemento DOM Temp para corresponder ao pai existente e poderia ser feito com bastante precisão na teoria. Também não sei o que resultaria de removê-los e adicioná-los novamente ao local existente. Como eles chegaram através de uma técnica innerHTML, estarei procurando usar essa abordagem diferente.
* NO ENTANTO * Nada disso foi necessário. Na verdade, funcionou como anunciado e retornou a altura correta !!!
Quando consegui tornar os menus visíveis novamente, o DOM retornou a altura correta de acordo com o layout do fluido na parte superior da página (279px). O código acima também usa getClientRects que retornam 280px.
Isso é ilustrado no instantâneo a seguir (tirado do Chrome depois de funcionar).
Agora não tenho idéia do por que esse truque de protótipo funciona, mas parece que sim. Como alternativa, getClientRects também funciona.
Suspeito que a causa de todo esse problema com esses elementos em particular tenha sido o uso do innerHTML em vez do appendChild, mas isso é pura especulação neste momento.