Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate Height on v-if in Vuejs using Transition

I'm using the following code to animate v-if element by reducing the height to 0px from. The animation works fine. But the problem is I've to specify the initial height of the element is CSS. For one element this is ok, But I want to apply this animation to multiple elements. How can I fix this? So that whatever be the height, animation works fine!

<transition name="fadeHeight" mode="out-in">
<div v-if="something">
<p>something over here where the height is not constant</p>
</div>
</transition>

.fadeHeight-enter-active,
.fadeHeight-leave-active {
  transition: all 0.2s;
  height: 230px;
}
.fadeHeight-enter,
.fadeHeight-leave-to
{
  opacity: 0;
  height: 0px;
}
like image 694
Gijo Varghese Avatar asked Mar 04 '17 02:03

Gijo Varghese


People also ask

How do I get element height in Vue?

To get an element's height with Vue. js, we can assign a ref to the element we want to get the height for. Then we can get the height with the clientHeight property of the element that's been assigned the ref. We assigned the ref with the ref prop set to a name.

Can you transition height in CSS?

We can't transition height , but we can transition max-height , since it has an explicit value. At any given moment, the actual height of the element will be the minimum of the height and the max-height .

How do you animate height in CSS?

For animate the "height" of element with CSS Transitions you need use "max-height". If use the "height: auto", the effect not works. Is necessary some value for the CSS create a CSS animate, and you can use "max-height" with a great value for emulate this effect.


2 Answers

It doesn't look like you've posted all the code, but hopefully I understand the goal.

Try moving the transition to the max-height property:

.fadeHeight-enter-active,
.fadeHeight-leave-active {
  transition: all 0.2s;
  max-height: 230px;
}
.fadeHeight-enter,
.fadeHeight-leave-to
{
  opacity: 0;
  max-height: 0px;
}

as long as you set a max height to be larger than the tallest element, it should accomplish what you need. Note that you may also want to use overflow:hidden as well. If you have dramatic variation of the actual height of the elements, this solution may not be the best, as it will make the animation duration/delay appear very different.

https://jsfiddle.net/7ap15qq0/4/

like image 174
ryantdecker Avatar answered Sep 18 '22 20:09

ryantdecker


@ryantdecker has the most common answer available. I prefer doing less code though and do class binding instead:

<template>
 <!-- isShowing either a data or computed... -->
 <div class="foo" :class="{'showing': isShowing', 'hidden': !isShowing}">
  <p>
   something over here where the height is not constant
  </p>
 </div>
</template>
...
<style>
.foo {
 height: auto;
 transition: max-height 0.5s;
 &.showing {
  max-height: 200px; //MUST BE MORE THAN height:auto
 }
 &.hidden {
  max-height: 0px;
 }
}
</style>

A few customizations that can be done for even more control are:

  1. Set :style="{'max-height': computedHeight}"
  2. Use ease-in and ease-out with two different transitions within the .showing and .hidden classes respectively.
  3. Use a cubic bezier transition speed for really long contents that collapse/expand

The first customization above can be used when you are using distinct items, like pictures, flex rows where the height can be seen via devtools and the height calculated. E.g.:

computed: {
 /**
  * @return {string} max height of the container in pixels if shown else zero
  */
 calcedHeight()
 {
   const elHeight = 80;
   const maxHeight = this.isShowing ? elHeight * this.elementCount : 0
   const maxHeightPx = maxHeight + 'px'
   return {
    'max-height': maxHeightPx
   }
 }
}

This could easily be made into a component with isShowing, elHeight, and elCount props at this point.

Cubic Bezier

I am giving this it's own section because it might be all that is needed in regards to crazy long elements (think 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);                                                 
}
like image 25
T.Woody Avatar answered Sep 19 '22 20:09

T.Woody