13

I have two elements, and the top one's visibility is controlled by a v-if on a simple boolean.

transition(name="fade")
    #element1(v-if="showFirst")
        p Foo

#element2
    p Bar

The first element is wrapped in a <transition> tag, exactly as per the Vue documentation.

However, while this does create a fading animation, the rest of the content on the page still jumps very jarringly.

How can I create a transition that will also smoothly transform the position of any and all siblings that follow?

A fiddle demoing this issue.

tony19
  • 125,647
  • 18
  • 229
  • 307
Emphram Stavanger
  • 4,158
  • 9
  • 35
  • 63

3 Answers3

13

You need to use a transition-group and key your dynamic div and static div

<transition-group name="fade">
  <div v-if="switc" key="dynamic" class="animated">
     ...
  </div>
  <div key="main-content" class="animated">
     ...
  </div>
</transition-group>

And use this css classes

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

.animated {
  transition: all 0.5s;
  /*display: flex;*/
  width: 100%;
}

The real trick is to change position to absolute when leaving, then any other content can take correct position.

To know more about how Vue animate things please see this FLIP explanation post

And please see this working fiddle https://jsfiddle.net/bjfhth7c/4/

Edit

By mistake I did set display: flex; in .animated class, that was causing to every inner element to render in a strange way.

So now, I completely remove .animate class, and instead apply transition: all 0.5s and width:100% to every direct inner element of .wrapper

My final scss looks like this:

.wrapper {
  display: flex;
  flex-direction: column;
  >* {
    transition: all 0.5s;
    width:100%;
  };
}

.fade-enter,
.fade-leave-active {
  opacity: 0;
  transform: translateY(-10px);
}

.fade-leave-active {
  position: absolute;
}

Flex layout is a extend subject, but in short for this particular case flex-direction: column is arranging elements one bellows previous one.

If one of those elements has absolute position will be ignored in flex layout so any other elements will be redistributed on available space.

Please see this guide about flexbox and last working fiddle hope it helps.

AldoRomo88
  • 2,056
  • 1
  • 17
  • 23
  • 1
    I think this is by far the best answer. It provides a robust solution for (possible) future requirement change. For example, how about there are other elements coming after `#element2`? How about the element being removed is in the middle of the list? How about adding a new element between `#element1` and `#element2`? Transition `max-height` is a good solution for the particular case, but if it's a problem from a serious product, I'd go with this one. – Leo Jan 24 '17 at 14:32
  • 1
    Thanks @Leo and yes with this solution is easy to add new divs before, after or between existing ones. Check this other example https://jsfiddle.net/AldoRomo88/q57dtx85/ – AldoRomo88 Jan 24 '17 at 14:44
  • 1
    Thanks for the answer, It looks good, Few issues I am facing due to display flex, for example I want to have a button of full width, but due to flex, I think, it behaves weirdly, check [this](https://jsfiddle.net/q57dtx85/1/). – Saurabh Jan 25 '17 at 14:02
  • 1
    So Will I have to give width 100% for each element as there are few more in my actual use-case or there some better way to do it, Can you also explain how it works in little more detail in the answer. – Saurabh Jan 25 '17 at 17:01
  • 1
    @AldoRomo88 Thanks for the update, sorry for my ignorance of CSS, can you explain what is the role of translateY setting -10px here? – Saurabh Jan 26 '17 at 06:19
  • Don't worry @Saurabh that's fine, `transform: translateY(-10px);` is a little enhancement to make elements to appear from 10px above his final position, and move that 10px to top while disappear – AldoRomo88 Jan 26 '17 at 14:25
3

You can use a slideDown/slideUp animation instead. For achieve this you don't need to know a height of a sliding element, the principles of max-height transition explained there.

So, as a result it will cause animated moving of elements below target.

Check out my example based on your fiddle.

Community
  • 1
  • 1
Panama Prophet
  • 1,027
  • 6
  • 6
  • 1
    When I start to use `.fade-leave-active`, why animation stops to work when I hide the div again, see [demo](https://jsfiddle.net/yzwh0od7/1/) – Saurabh Jan 25 '17 at 12:25
  • 1
    Because `*-leave-active` class applying to the target element during the whole animation cycle, but you need to control only start and end values, that's why i attached an example. Check the transition classes section in documentation - https://vuejs.org/v2/guide/transitions.html#Transition-Classes – Panama Prophet Jan 25 '17 at 13:02
  • 1
    So this two way animation not possible with Vue less than 2.1.8, when .fade-leave-to class was not there? – Saurabh Jan 25 '17 at 14:12
  • 1
    who said?) check the example here: http://v1.vuejs.org/guide/transitions.html#CSS-Transitions – Panama Prophet Jan 25 '17 at 15:31
  • 1
    There may be error in my explaining, `v-enter-to` is not available before 2.1.8, which you are using in your fiddle, I am using 2.0.0, so I only want to use `v-leave-active`, when I modified your fiddle as [this](https://jsfiddle.net/yzwh0od7/1/): transition works when expanding but on collapse there is no animation. – Saurabh Jan 25 '17 at 16:21
  • oh, sorry, really misunderstood. same behavior, catch it - https://jsfiddle.net/panamaprophet/1ov4tjr1/ – Panama Prophet Jan 25 '17 at 16:55
  • There is something still weird, when you first click on `switch` it expands, it is still focussed, if you click outside, so focus will go away from the `switch`, now again press `switch`, than no animation. Works fine when click on focussed button. – Saurabh Jan 25 '17 at 16:58
1

vue js provides different transition classes, you have to use those properly to smooth the transition, I have tried with your example in this fiddle with some CSS, have a look.

.fade-enter-active, .fade-leave-active {
  transition: all .5s;
  height: 100px;
  opacity: 0.5;
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
  height: 0px;
  opacity: 0;
}

Some details from documentation:

There are six classes applied for enter/leave transitions.

  1. v-enter: Starting state for enter. Added before element is inserted, removed one frame after element is inserted.
  2. v-enter-active: Active state for enter. Applied during the entire entering phase. Added before element is inserted, removed when transition/animation finishes. This class can be used to define the duration, delay and easing curve for the entering transition.
  3. v-enter-to: Only available in versions >=2.1.8. Ending state for enter. Added one frame after element is inserted (at the same time v-enter is removed), removed when transition/animation finishes.
  4. v-leave: Starting state for leave. Added immediately when a leaving transition is triggered, removed after one frame.
  5. v-leave-active: Active state for leave. Applied during the entire leaving phase. Added immediately when leave transition is triggered, removed when the transition/animation finishes. This class can be used to define the duration, delay and easing curve for the leaving transition.
  6. v-leave-to: Only available in versions >=2.1.8. Ending state for leave. Added one frame after a leaving transition is triggered (at the same time 7. v-leave is removed), removed when the transition/animation finishes.

You can as well use CSS animations where you can provide on different phases of transition what will be your css property to make your transitions more smooth, like following and demo fiddle:

.fade-enter-active {
  animation: bounce-in .5s;
}
.fade-leave-active {
  animation: bounce-out .5s;
}
@keyframes bounce-in {
  0% {
    height: 5px;
  }
  30% {
    height: 30px;
  }
  50% {
    height: 50px;
  }
  100% {
    height: 100px;
  }
}
@keyframes bounce-out {
  0% {
    height: 90px;
    }
  50% {
    height: 50px;
  }
  100% {
    height: 0px;
  }
}
tony19
  • 125,647
  • 18
  • 229
  • 307
Saurabh
  • 71,488
  • 40
  • 181
  • 244
  • 1
    Thanks, but this does require me to specify a height in CSS for the element; this isn't really possible in my case, as the element may be of any height due to its content. – Emphram Stavanger Jan 19 '17 at 17:01
  • 1
    @EmphramStavanger Can you create your case in my fiddle so that I can play around with it. – Saurabh Jan 19 '17 at 17:08