Getting the Height of a Hidden Element
Sometimes, we need to animate the height of a currently closed or hidden element, so that it appears to slide open. The use case of an accordion comes to mind. Back in the time of jQuery, we had a handy function called slideToggle
which was a single function that would animate a closed element open and closed. Today, we aren't using jQuery as much, and besides we can handle the animation with a much lighter touch using CSS.
We run into an issue, however, because CSS doesn't have a way to animate to an arbitrary height. You can animate the height using:
.animate-height {transition: height .2s ease;/* or */transition: max-height .2s ease;}
Both of these will transition between two fixed heights, but we can't animate to or from max-height: none
or height: auto
. So, we can't animate to an arbitrary sized element. What we can do is figure out how high the element should be once it's visible at its full height.
To accomplish this we are going to use a function called getHiddenHeight
:
function getHiddenHeight(el) {if(!el?.cloneNode) {return null;}const clone = el.cloneNode(true);Object.assign(clone.style, {overflow: 'visible',height: 'auto',maxHeight: 'none',opacity: '0',visibility: 'hidden',display: 'block',});el.after(clone);const height = clone.offsetHeight;clone.remove();return height;}
This function takes in an HTML element and returns its full height if it were visible. It briefly creates an invisible clone element inside the element's parent, measures its height and removes it.
Let's step through this.
First, we make sure that we actually have an element and return null
if we don't.
if(!el?.cloneNode) {return null;}
Next, we clone the element, so we don't mess up the original with our changes.
const clone = el.cloneNode(true);
We then need to make sure that the clone actually has a height, so we override a bunch of properties that may prevent an accurate reading. Here we're using Object.assign
to override these properties on the clone.style
object.
Object.assign(clone.style, {overflow: 'visible',height: 'auto',maxHeight: 'none',opacity: '0',visibility: 'hidden',display: 'block',});
Then, we add the clone to the element's parent right after the real element and measure its height.
el.after(clone);const height = clone.offsetHeight;
Finally, we remove the clone and return the height.
clone.remove();return height;
Now, that we know what height the element needs to be, we can use JavaScript to set the height
or max-height
to that value (making sure we add our units to the end);
el.style.height = `${getHiddenHeight(el)}px`;// orel.style.maxHeight = `${getHiddenHeight(el)}px`;
We could set a button click to toggle between this value and 0 to slide the element opened and closed.
There is one thing to note here: If the content changes or if the viewport changes, we may end up with our container being too small. There are a number of ways around this, though:
- You can recalculate the height.
- You can set
overflow: auto
to allow the content to scroll. - You can also remove the set height from the element once it is fully opened. This way the element can change size as needed.
So, there you have it: A way to find the height of a hidden element. As an added bonus, I have create a git repo and an npm package for this function:
https://github.com/RobotsPlay/get-hidden-height
npm install get-hidden-height