So I am trying to animate an SVG. When applying animation delay to each path it works properly in v-leave-active class but doesn't work at all in v-enter-active and behaves weird. Check the code below and please help. Run the snippet and click on the button "click" then again click to see the exact problem happening.
const { createApp } = Vue
createApp({
data() {
return {
show: false
}
}
}).mount('.app')
.svg{
max-width: 100px;
margin-left: 50px
}
/* Enter Animation */
.forwardOne-enter-active{
animation: fade-in 0.2s;
}
.forwardTwo-enter-active{
animation: fade-in 0.2s;
animation-delay: 0.3s;
}
.forwardThree-enter-active{
animation: fade-in 0.2s;
animation-delay: 0.6s;
}
/*Leave Animation*/
.forwardOne-leave-active {
animation: fade-in 0.2s reverse;
}
.forwardTwo-leave-active {
animation: fade-in 0.2s reverse;
animation-delay: 0.3s;
}
.forwardThree-leave-active {
animation: fade-in 0.2s reverse;
animation-delay: 0.6s;
}
@keyframes fade-in {
0% {
opacity: 0;
}
50% {
transform: 0.5;
}
100% {
transform: 1;
}
}
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div class="app">
<button class="right" @click="show = !show">
Click
</button>
<button class="svg">
<svg fill="#000" viewBox="0 0 24 24" stroke="3px">
<g>
<Transition name="forwardThree">
<path v-show="show" d="M15.14,5.46V18.57l8.32-6.64ZM15.87,7l6.42,5-6.42,5.12Z"/>
</Transition>
<Transition name="forwardTwo">
<path v-show="show" d="M15.51,11.37l-.37-.28L7.86,5.43V18.54l7.28-5.81.73-.58v-.49ZM8.6,17V6.92l6.41,5Z"/>
</Transition>
<Transition name="forwardOne">
<path v-show="show" d="M8.23,11.41l-.37-.29L.54,5.43V18.54l7.32-5.85.37-.29.37-.3v-.41ZM1.28,17V6.92l6.41,5Z"/>
</Transition>
</g>
</svg>
</button>
</div>
You can see that first time it does not work but on second click it works properly. I have no idea why this is happening
There are several problems with the code you posted, each of them breaking the animation:
<svg>
is rendered outside the <button>
(at least in Chrome)@keyframe
is malformed. You're animating from opacity: 0
to transform: 1
.transform: 1
is not valid and, even if it was, you can't animate a property into another property. What should we expect halfway through the animation? opacform: 0.5
?opacity: 0
to opacity: 1
opacity: 0
on .{x}-enter-active
classes. It is necessary, for the ones which have delay, because while they are being delayed they will have whatever opacity
the element has, which, by default, is 1
.See it working:
const {
createApp
} = Vue
createApp({
data() {
return {
show: false
}
}
}).mount('#app')
.svg svg {
height: 2rem;
width: auto;
}
.forwardOne-enter-active,
.forwardTwo-enter-active,
.forwardThree-enter-active {
animation: .2s fade-in;
opacity: 0;
}
.forwardOne-leave-active,
.forwardTwo-leave-active,
.forwardThree-leave-active {
animation: .2s fade-in reverse;
}
.forwardTwo-enter-active,
.forwardTwo-leave-active {
animation-delay: .3s;
}
.forwardThree-enter-active,
.forwardThree-leave-active {
animation-delay: .6s;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="app">
<button class="right" @click="show = !show">
Click
</button>
<button class="svg">
<svg fill="#000" viewBox="0 0 24 24" stroke="3px">
<Transition name="forwardThree">
<path v-show="show" d="M15.14,5.46V18.57l8.32-6.64ZM15.87,7l6.42,5-6.42,5.12Z"/>
</Transition>
<Transition name="forwardTwo">
<path v-show="show" d="M15.51,11.37l-.37-.28L7.86,5.43V18.54l7.28-5.81.73-.58v-.49ZM8.6,17V6.92l6.41,5Z"/>
</Transition>
<Transition name="forwardOne">
<path v-show="show" d="M8.23,11.41l-.37-.29L.54,5.43V18.54l7.32-5.85.37-.29.37-.3v-.41ZM1.28,17V6.92l6.41,5Z"/>
</Transition>
</svg>
</button>
</div>
And here's a way to avoid the CSS class boilerplate, using SCSS and creative selectors.
Side notes:
It's sub-par to use a class selector to mount your app. It's not so much it doesn't work, but the fact Vue treats that selector as an ID selector (it mounts the app in the first element matching the selector).
If you have more than one element with this class, the app will only be mounted in the first one. By using a class selector, no IDE or code validator will warn you about the duplicity of the selector and, as a developer, you probably want to know about it.
In my mind, using class selectors to mount Vue apps is like using dots in class names. It works, but it's fragile, therefore an open invitation to future subtle bugs and headaches.
technically, it's sub-par to develop in FF:
I like Mozilla and I use some of their products. But it makes little sense to use Firefox while developing (unless I'm developing something aimed at FF users, of course).