Как сделать двустороннюю анимацию?
На кружке ниже я сделал анимацию и добавляю ему класс при клике, но при повторном клике я хочу чтобы он обратно плавно возвращался в исходную позицию, а он просто резко встаёт в исходную позицию. Как сделать плавное возвращение назад?
const circle = document.querySelector('.circle');
circle.addEventListener('click', function() {
this.classList.toggle('circle-animate')
})
@keyframes circle-animate {
0% {
margin: 0;
}
50% {
margin-left: 200px;
margin-top: 0;
}
to {
margin-left: 200px;
margin-top: 50px;
}
}
.circle {
width: 90px;
height: 90px;
background-color: #fff;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
box-shadow: 0 0 25px 3px #000;
}
.circle-animate {
animation-name: circle-animate;
animation-duration: 2s;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
body {
background-color: gray;
}
<div class="circle">Кликни на меня</div>
ЗЫ: Сделал чтото подобное( https://jsfiddle.net/bpw36tnL/58/ ), но думаю это костыли и есть баг - если кликнуть по середине анимации она прервётся и кружок перейдёт в исходное состояние другой анимации. Не красиво
Ответы (3 шт):
const circle = document.querySelector('.circle');
circle.addEventListener('click', function() {
if (this.classList.contains('circle-animate-forward')){
this.className = 'circle circle-animate-back deactive'
return
} else {
this.className = 'circle circle-animate-forward deactive'
return
}
})
circle.addEventListener('animationend',function(){
this.classList.remove('deactive')
})
@keyframes circle-animate-forward {
0% {
margin: 0;
}
50% {
margin-left: 200px;
margin-top: 0;
}
to {
margin-left: 200px;
margin-top: 50px;
}
}
@keyframes circle-animate-back {
0% {
margin-left: 200px;
margin-top: 50px;
}
50% {
margin-left: 200px;
margin-top: 0;
}
to {
margin: 0;
}
}
.circle {
width: 90px;
height: 90px;
background-color: #fff;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
box-shadow: 0 0 25px 3px #000;
}
.circle.deactive{
pointer-events: none;
}
.circle-animate-forward {
animation-name: circle-animate-forward;
animation-duration: 2s;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
.circle-animate-back {
animation-name: circle-animate-back;
animation-duration: 2s;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
body {
background-color: gray;
}
<div class="circle">Кликни на меня</div>
Как вариант слушать события начала и конца анимации. Примерно вот так:
const circle = document.querySelector('.circle');
let direction = "forward";
let isAnimationEnd = true;
circle.addEventListener('animationstart', () => {
isAnimationEnd = false;
});
circle.addEventListener('animationend', () => {
isAnimationEnd = true;
});
circle.addEventListener('click', function() {
if (isAnimationEnd && direction === "forward") {
this.classList.remove('circle-animate-out');
this.classList.add('circle-animate-in');
direction = "back";
}
else if (isAnimationEnd && direction === "back") {
this.classList.remove('circle-animate-in');
this.classList.add('circle-animate-out');
direction = "forward";
}
})
@keyframes circle-animate-in {
0% {
margin: 0;
}
50% {
margin-left: 200px;
margin-top: 0;
}
to {
margin-left: 200px;
margin-top: 50px;
}
}
@keyframes circle-animate-out {
0% {
margin-left: 200px;
margin-top: 50px;
}
50% {
margin-left: 200px;
margin-top: 0;
}
to {
margin: 0;
}
}
.circle {
width: 90px;
height: 90px;
background-color: #fff;
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
text-align: center;
box-shadow: 0 0 25px 3px #000;
transition: .3s ease;
}
.circle-animate-in {
transition: .3s ease;
animation-name: circle-animate-in;
animation-duration: 2s;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
.circle-animate-out {
transition: .3s ease;
animation-name: circle-animate-out;
animation-duration: 2s;
animation-timing-function: ease;
animation-fill-mode: forwards;
}
body {
background-color: gray;
}
<div class="circle">Кликни на меня</div>
Можно пойти другим путём - если анимация несложная (как в данном вопросе), то использовать transition вместо animation. Выполняется главное условие - реверс с места клика, но...
Есть одна большая проблема - замирание анимации после клика, в ожидании окончания задержек, которые нужны для правильного порядка шагов. Если это не критично или анимации короткие, то попробуйте вариант ниже:
const circle = document.querySelector('.circle');
circle.addEventListener('click', function() {
this.classList.toggle('reverse');
});
body { background-color: gray; }
.circle {
display: flex;
align-items: center;
justify-content: center;
height: 90px; width: 90px;
border-radius: 50%;
text-align: center;
background-color: #fff;
box-shadow: 0 0 25px 3px #000;
user-select: none;
margin: 0;
transition: margin-left 1s linear .5s, margin-top .5s linear;
}
.circle.reverse {
margin-left: 200px; margin-top: 50px;
transition: margin-left 1s linear, margin-top .5s linear 1s;
}
<div class="circle">Кликни на меня</div>