Why does transition-group animate opacity but not animate height?

Viewed 57

the code below animates the element you click on, but I want it to smoothly decrease the height to zero as well. Unfortunately, the height does not change, but everything works with opacity.

height: 0 !improtant; //does not help to solve the problem

<template>
  <transition-group name="msgAnimation" tag="div">
    <div v-for="(obj, i) in messages" :key="obj.key" class="wrapper">
      <div class="wrapper__block" @click="messages.splice(i, 1)">
        {{ obj.msg }}
      </div>
    </div>
  </transition-group>
</template>
<style lang="css">
.msgAnimation-enter-active,
.msgAnimation-leave-active {
  transition: all 5s;
}
.msgAnimation-enter,
.msgAnimation-leave-to {
  height: 0;
  opacity: 0;
}
.wrapper {
  width: 100%;
  height: 9vmin;
}

.wrapper__block {
  background: green;
  height: 9vmin;
  width: 100%;
}
</style>
<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      totalAmount: 0,
      messages: [{ key: 0, msg: "Are u hacker" }],
    };
  },
};
</script>

2 Answers

Your CSS rules was declared after your animation

const example = {
  data() {
    return {
      totalAmount: 0,
      messages: [{
          key: 0,
          msg: "Are u hacker"
        },
        {
          key: 1,
          msg: "Are u hacker"
        }
      ],
    };
  },
};

const app = new Vue(example);
app.$mount("#app");
.msgAnimation-enter-active,
.msgAnimation-leave-active {
  transition: all 5s;
}

.wrapper {
  width: 100%;
  height: 9vmin;
  overflow:hidden;
}

.wrapper__block {
  background: green;
  width: 100%;
}

.msgAnimation-enter,
.msgAnimation-leave-to {
  opacity: 0;
  height: 0;
}
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>

<div id="app">
  <transition-group name="msgAnimation" tag="div">
    <div v-for="(obj, i) in messages" :key="obj.key" class="wrapper">
      <div class="wrapper__block" @click="messages.splice(i, 1)">
        {{ obj.msg }}
      </div>
    </div>
  </transition-group>
</div>

You're not limiting overflow of .wrapper, and you have a height specified in .wrapper__block. Thus, even if .wrapper goes smoothly to 0, its child will not.

Setting height: 100%; on .wrapper__block, or setting overflow: hidden on .wrapper should do the trick.

<template>
  <transition-group name="msgAnimation" tag="div">
    <div v-for="(obj, i) in messages" :key="obj.key" class="wrapper">
      <div class="wrapper__block" @click="messages.splice(i, 1)">
        {{ obj.msg }}
      </div>
    </div>
  </transition-group>
</template>
<style lang="css">
.msgAnimation-enter-active,
.msgAnimation-leave-active {
  transition: all 5s;
}
.msgAnimation-enter,
.msgAnimation-leave-to {
  height: 0;
  opacity: 0;
}
.wrapper {
  width: 100%;
  height: 9vmin;
}

.wrapper__block {
  background: green;
  height: 100%;
  width: 100%;
}
</style>
<script>
export default {
  name: "HelloWorld",
  data() {
    return {
      totalAmount: 0,
      messages: [{ key: 0, msg: "Are u hacker" }],
    };
  },
};
</script>

Alternatively, if you don't mind distortion during the animation, it's a lot more performant to animate transform: scaleY(0), as transform and opacity are applied at the Composition step in CSS, you prevent a lot of in-between style calculations, making your app noticeably faster whn you have several thousand messages.

Related