i'm working on a project where i have to render some ponents with an enter and leave animation, when a ponent enters the screen it has to enter form the bottom, and when it leaves, it has to do it going upwards, the desired behavior is that when i change the :is property of the ponent tag, the current ponent goes upwards and the next one es from the bottom, the code looks like this:
<template>
<div class="home">
<transition name="section">
<ponent :is="activeSection"></ponent>
</transition>
</div>
</template>
<script>
import p1 from './p1';
import p2 from './p2';
export default {
ponents: {
p1,
p2
},
data() {
activeSection: 'p1'
}
</script>
<style scoped>
.section-enter {
top: 100vh;
}
.section-enter-to {
top: 0vh;
}
.section-enter-active {
animation-name: 'slideIn';
animation-duration: 1s;
}
.section-leave {
top: 0vh;
}
.section-leave-active {
animation-name: 'slideOut';
animation-duration: 1s;
}
.section-leave-to {
top: -100vh;
}
@keyframes slideIn {
from {
top: 100vh;
}
to {
top: 0
}
}
@keyframes slideOut {
from {
top: 0vh;
}
to {
top: -100vh;
}
}
</style>
but the actual behavior is that the first ponent goes upwards but the second appears inmediatly after without animation.
if i render one at a time (not destructing one and rendering another with the same action) everything works perfectly. I dont know what is happening.
i'm working on a project where i have to render some ponents with an enter and leave animation, when a ponent enters the screen it has to enter form the bottom, and when it leaves, it has to do it going upwards, the desired behavior is that when i change the :is property of the ponent tag, the current ponent goes upwards and the next one es from the bottom, the code looks like this:
<template>
<div class="home">
<transition name="section">
<ponent :is="activeSection"></ponent>
</transition>
</div>
</template>
<script>
import p1 from './p1';
import p2 from './p2';
export default {
ponents: {
p1,
p2
},
data() {
activeSection: 'p1'
}
</script>
<style scoped>
.section-enter {
top: 100vh;
}
.section-enter-to {
top: 0vh;
}
.section-enter-active {
animation-name: 'slideIn';
animation-duration: 1s;
}
.section-leave {
top: 0vh;
}
.section-leave-active {
animation-name: 'slideOut';
animation-duration: 1s;
}
.section-leave-to {
top: -100vh;
}
@keyframes slideIn {
from {
top: 100vh;
}
to {
top: 0
}
}
@keyframes slideOut {
from {
top: 0vh;
}
to {
top: -100vh;
}
}
</style>
but the actual behavior is that the first ponent goes upwards but the second appears inmediatly after without animation.
if i render one at a time (not destructing one and rendering another with the same action) everything works perfectly. I dont know what is happening.
Share Improve this question edited Jan 20, 2019 at 18:53 tony19 139k23 gold badges277 silver badges347 bronze badges asked Jan 18, 2019 at 19:27 Carlos PisarelloCarlos Pisarello 1,2846 gold badges23 silver badges41 bronze badges 2- 1 could you please put this somewhere like codesandbox so its easier to recreate and look into? – Gowri Commented Jan 19, 2019 at 1:40
-
Hey, in my case, I just had to add an
appear
attribute to my transition. Hope it may help the others having this issue! – l-portet Commented Sep 10, 2021 at 19:21
2 Answers
Reset to default 5There are a few problems in your CSS.
CSS Transitions and CSS Animations
A transition can be implemented using either CSS Transitions or CSS Animations. Your CSS incorrectly mixes the two concepts in this case.
In particular, the slideIn
keyframes and .section-enter
/.section-enter-to
rules are effectively performing the same task of moving .section
into view. However, this is missing a transition
rule with a non-zero time, required to animate the change, so the change occurs immediately. The same issue exists for the slideOut
keyframes and leave
rules.
.section-enter {
top: 100vh;
}
.section-enter-to {
top: 0;
}
.section-enter-active {
transition: .5s; /* MISSING RULE */
}
.section-leave {
top: 0;
}
.section-leave-to {
top: -100vh;
}
.section-leave-active {
transition: .5s; /* MISSING RULE */
}
Removing the keyframes, and adding the missing rules (as shown above) would result in a working CSS Transition.
demo 1
Using CSS Animations
Alternatively, you could use keyframes with CSS Animations, where the animation is applied only by the *-active
rules, and no *-enter
/*-leave
rules are used. Note your question contained unnecessary quotes in animation-name: 'slideIn';
, which is invalid syntax and would be silently ignored (no animation occurs). I use a simpler shorthand in the following snippet (animation: slideIn 1s;
).
.section-enter-active {
animation: slideIn 1s;
}
.section-leave-active {
animation: slideOut 1s;
}
@keyframes slideIn {
from {
top: 100vh;
}
to {
top: 0;
}
}
@keyframes slideOut {
from {
top: 0;
}
to {
top: -100vh;
}
}
demo 2
Optimizing CSS Transitions
You could also tweak your animation performance by using translateY
instead of transitioning top
.
/* top initially 0 in .wrapper */
.section-leave-active,
.section-enter-active {
transition: .5s;
}
.section-enter {
transform: translateY(100%);
}
.section-leave-to {
transform: translateY(-100%);
}
demo 3
Use a Mixin
Thanks for the explanation @tony19
please use a mixin for this so the logic can be repeated easily.
Also, your slideIn and slideOut can be bined by using reverse:
@mixin animationmixin($type:'animation', $style:'', $duration:1s) {
@keyframes #{$type}-#{$style} { // register animation
0% { opacity: 1; transform: none; } // reset style
100% { @content; } // custom style
}
.#{$style} { // add '.section'
&-enter-active, &-leave-active { // add '.section-enter-active', ...
transition: #{$duration};
}
&-enter, &-leave-to {
animation: #{$type}-#{$style} #{$duration}; // use animation
}
&-leave, &-enter-to {
animation: #{$type}-#{$style} #{$duration} reverse; // use animation in reverse
}
}
}
Use it like this:
@include animationmixin($style:'section') { // set custom styling
transform: translateY(100%);
};
And like this:
@include animationmixin($style:'fade') {
opacity: 0;
transform: scale(0.9);
};