@ryantdecker seems to have the most popular solution, but personally, I like to keep my code concise by utilizing class binding instead:
<template>
<!-- isShowing either data or computed... -->
<div class="foo" :class="{ showing: isShowing, hidden: !isShowing }">
<p>
content here with variable height
</p>
</div>
</template>
...
<style>
.foo {
height: auto;
transition: max-height 0.5s;
&.showing {
max-height: 200px; /* MUST BE GREATER THAN height:auto */
}
&.hidden {
max-height: 0px;
}
}
</style>
If you want more customization options for further control, consider these:
- Include
:style="{'max-height': computedHeight}"
- Implement different easing functions such as
ease-in
and ease-out
in separate transitions
within the .showing
and .hidden
classes.
- Use a cubic bezier transition speed for handling extremely long collapsing/expanding elements
The first modified option is useful when dealing with distinct items where heights are known, like images or flex rows that can be inspected using devtools. Example:
computed: {
/**
* @return {string} maximum height of the container in pixels if visible else zero
*/
calcedHeight()
{
const elHeight = 80;
const maxHeight = this.isShowing ? elHeight * this.elementCount : 0
const maxHeightPx = maxHeight + 'px'
return {
'max-height': maxHeightPx
}
}
}
At this stage, it's easy to convert this into a component with props like isShowing
, elHeight
, and elCount
.
Cubic Bezier
This section focuses on using cubic bezier transitions which can be effective for handling very tall elements (e.g., 5000px max-heights
):
&.showing {
transition: all 0.6s cubic-bezier(1, 0.01, 1, 0.01);
}
&.hidden {
transition: all 0.6s cubic-bezier(0.01, 1, 0.01, 1);
}