Reputation: 875
Is there any way to get an element's height prior to appending it to the DOM? I know that clientHeight doesn't work as I've tried and it always returns 0. Are there other methods that may return the height or does the element have to be a part of the DOM in order for the height to be calculated?
This is a sample of what I'm going for:
function test(a) {
var a=document.createElement(a)
a.style.top=(window.innerHeight/2-a.clientHeight/2)+'px' //fixed position in CSS
document.body.appendChild(a)
}
*Note: This is only a simplified version of the function I'm working on in order to project what I'm trying to achieve without all of the unneeded mess.
Upvotes: 48
Views: 32754
Reputation: 11
Before adding the element to the DOM I don't think it is possible, unless you know all the variables involved beforehand (unlikely).
However it is possible to get it's height before it gets displayed on the screen.
The screens have a refresh rate (maximum number of images shown per second) so it is not possible to render the page at each change made by the DOM.
You can ask to the DOM to notify you right before the repaint by calling requestAnimationFrame. Here you can get the element's properties and change them.
You can even cancel this frame by calling cancelAnimationFrame.
https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame
Upvotes: 0
Reputation: 130790
If the height of the DOM node is/can be dynamic then you probably cannot measure it before it exists in the DOM, unless you somehow take into consideration all possible scenarios (font-size, padding/margin/border, actual size, etc.)
A viable option is to inject the node into the DOM, visually hidden, and measure things, and only then reveal it.
Here is a working demo of how to measure an element by briefly adding it to the DOM and inspecting its height, then removing it. This method might be costly since the node is cloned, so the added styles won't affect it afterwards and all DOM events will be removed from it.
If the inspected node has a lot of sub-nodes, this might not be efficient, but stil can be quite handy.
function getNodeHeight(node) {
var height, clone = node.cloneNode(true)
// hide the meassured (cloned) element
clone.style.cssText = "position:fixed; top:-9999px; opacity:0;"
// add the clone to the DOM
document.body.appendChild(clone)
// meassure it
height = clone.clientHeight
// cleaup
clone.parentNode.removeChild(clone)
return height
}
var newDiv = document.createElement("div");
newDiv.innerHTML = `Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
<h1>deserunt mollit anim id est laborum.<h1>`
// print the height of "newDiv"
console.log( getNodeHeight(newDiv) )
Upvotes: 7
Reputation: 56654
Elements don't have a height, in any real sense, until they've been added to the DOM, as their styles cannot be evaluated until then.
You can get around this easily enough using visibility: hidden
so that the element can be added to the DOM (and its height determined) without causing visible flickering.
function test(a) {
var a = document.createElement(a);
a.style.visibility = 'hidden';
document.body.appendChild(a);
a.appendChild(document.createTextNode('Hello'));
a.style.fontStyle = 'italic';
a.style.top=(window.innerHeight/2 - a.clientHeight/2) + 'px';
a.style.visibility = '';
return a;
}
test('p').style.background = '#0f0';
p { position: absolute; top: 0; left: 0; }
(This is working on the assumption that you're using top
because the element is absolutely positioned or fixed. If it weren't, you'd need to make it so temporarily.) Hidden elements still take up space in the DOM (so their sizes must be calculated), but cannot actually be seen by the user.
Upvotes: 51