Transition-group leave transition w/ position: absolute jumping to top-left (FLIP)


#1

Hey there,

I’ve run into a frustrating issue where my list items that are leaving are jumping to the top-left of its container while using the FLIP move/leave technique.

position: absolute; is necessary on list-leave-active in order for the rest of the items to move into place, however it’s also causing the leaving element to jump to the top-left of its parent container before its leave transition starts (which is to fade and translate down 10px, in this case).

I need my list to use flexbox in order to get the items to flow and wrap easily, so positioning my elements absolutely in the grid isn’t an option. I thought the point of implementing FLIP was for elements to retain their position properly and enter/leave/move gracefully with that in mind.

Here’s a CodePen with an example reproducing the issue on the latest version of Vue (2.3.3).
Click on the items to remove them and see the issue:

Any help or suggestions would be appreciated. Thanks!


#2

What web browser are you using? I’m on Chrome and it seems to be working for me. The leaving element moves to the top left (first element) while fading? I dont see any jumping of the element.


#3

Apologies—the problem is that it’s animating to the top-left, when it should stay in place, fade out, and slide down 10px per the list-leave-to CSS class. This is being caused by the element having position: absolute on it during list-leave-active so that the other list items can animate into their places.

Does that make more sense?


#4

For now, I ended up using a beforeLeave hook on the transition to size and position the element before the transition starts. The convenience of Vue’s FLIP behavior is defeated without this being the default behavior.

<transition-group
  @before-leave="beforeLeave">
  ...
</transition>
methods: {
  beforeLeave(el) {
    const {marginLeft, marginTop, width, height} = window.getComputedStyle(el)
    el.style.left = `${el.offsetLeft - parseFloat(marginLeft, 10)}px`
    el.style.top = `${el.offsetTop - parseFloat(marginTop, 10)}px`
    el.style.width = width
    el.style.height = height
  }
}

Hopefully this is helpful to someone with the same issues!


#5

Created an account just to say thank you @docmars! This was driving me crazy :slight_smile: