Search code examples
vue.jsvuejs3css-transitionsvue-transitionsvuejs-transition-group

Why elements appears from top-left corner with TransitionGroup in Vue 3?


I'm currently trying to integrate animations on a small component that contains: a title, an image and a block of buttons.

The rules are as follows:

  • Initially, we only have the title and the image,
  • When you hover over the component, the title disappears towards the top, the image rises and takes its place, and the buttons appear from the bottom,
  • When we stop hovering over the component, the title reappears from the top, the image goes back down, taking the place of the buttons, and the buttons disappear towards the bottom.

At present, for some unknown reason, the components (title and buttons) systematically come from the top left corner of the page. What's more, the image is only animated when the hover stops, not when it starts.

Here's a link to the VueJS playground to show you how it works

Your help will be greatly appreciated

I already tried :

  • Type modification in TransitionGroup (transition, animation)
  • Putting the same key on each component, even if this is prohibited by the official documentation, reactivates the animation on the image at the beginning and end.
  • Using position: absolute
  • Using transition-origin
  • Using perspective-origin
  • Force top and left attributes via @beforeLeave hook
  • Integrate the component in an iFrame, and notice that the components (title and buttons) appear from the top left corner of the iFrame (no surprise there).

Solution

  • When you use v-if instead of v-show, the elements stop coming in from the top left. Also, I think type="animation" is only necessary when you use CSS animations and transitions together, but you are only using transitions.

    Finally, you can position the where you want to move them from and to. To smoothen the transition, use absolute position on the leaving elements, so the space is vacated immediately:

    .slide-fade-leave-active{
      position: absolute;
    }
    .slide-fade-enter-from,
    .slide-fade-leave-to {
      opacity: 0;
      transform: translateY(-100px);
    }
    

    Here it is in a playground. Hope it helps