I need to measure the offsetHeight of a div that is inside of a hidden element.
-
A helper function ---
function getElementHeight(el) {
var clone = el.cloneNode(true);
var width = el.getBoundingClientRect().width;
clone.style.cssText = 'position: fixed; top: 0; left: 0; overflow: auto; visibility: hidden; pointer-events: none; height: unset; max-height: unset; width: ' + width + 'px';
document.body.append(clone);
var height = clone.getBoundingClientRect().height + 'px';
clone.remove();
return height;
}
Creates a clone, appends it to the DOM (hidden), takes the height, then removes it.
Position of fixed and the top/left are in case your app allows scrolling at the body-level - it attempts to prevent a scrollbar rave party - can remove if you handle scrolling in children elements.
Overflow, height, and max-height settings to attempt to 'reset' height settings and let it be it's natural height on the clone.
Visibility for the obvious and pointer-events as a 'just in case' the rendering of the element takes a while and don't want to interrupt user-input.
An example having an 'accordion-like' animated open/close allowing for dynamic heights.
function getElementHeight(el) {
var clone = el.cloneNode(true);
clone.style.cssText = 'position: fixed; top: 0; left: 0; overflow: auto; visibility: hidden; pointer-events: none; height: unset; max-height: unset';
document.body.append(clone);
var height = clone.getBoundingClientRect().height + 'px';
clone.remove();
return height;
}
var expanded = false;
function toggle() {
var el = document.getElementById('example');
expanded = !expanded;
if (expanded) {
el.style.maxHeight = getElementHeight(el);
// Remove max-height setting to allow dynamic height after it's shown
setTimeout(function() {
el.style.maxHeight = 'unset';
}, 1000); // Match transition
} else {
// Set max height to current height for something to animate from
el.style.maxHeight = getElementHeight(el);
// Let DOM element update max-height, then set to 0 for animated close
setTimeout(function() {
el.style.maxHeight = 0;
}, 1);
}
}
#example {
overflow: hidden;
max-height: 0;
transition: max-height 1s;
}