Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS animations - How to toggle direction with one keyframes declaration

I would like a div to animate to the right when a button is clicked, then animate again to the left when the same button is clicked. I would like to use only one keyframes declaration. Is this possible by swapping classes?

I've tried this in CodePen, but unfortunately, the div snaps back after the first animation, then refuses to animate the second time.

I'm not using CSS transitions because I want to be able to use features of CSS animations like a bouncing effect.

window.addEventListener("load", function() {
  var movedOver = false;

  document.querySelector("button").addEventListener("click", function() {
    var buttonEl = document.querySelector(".one");

    if (movedOver) {
      buttonEl.classList.remove("do-the-slide");
      buttonEl.classList.add("do-the-slide-back");

    } else {
      buttonEl.classList.remove("do-the-slide-back");
      buttonEl.classList.add("do-the-slide");
    }

  });

});
.container {
  position: absolute;
  perspective: 800px;
  >div {
    position: absolute;
    padding: 20px;
    text-align: center;
    width: 100px;
  }
  >div.do-the-slide {
    animation: moveOver 1s ease-out;
  }
  >div.do-the-slide-back {
    animation: moveOver 1s reverse ease-out;
  }
  >.one {
    background: red;
  }
}

button {
  margin-top: 100px;
}

@keyframes moveOver {
  from {
    transform: translateX(0px);
  }
  to {
    transform: translateX(100px);
  }
}
<div class="container">
  <div class="one">One</div>
</div>

<button>Clicky</button>

Codepen: http://codepen.io/anon/pen/Vaadao

like image 300
risingtiger Avatar asked Mar 09 '16 18:03

risingtiger


2 Answers

Alright, so after fiddling with this for a while, I've come up with what I consider an acceptable solution for using one keyframes declaration to drive both directions of animations. The key to this was forcing the browser essentially reset through a redraw, as explained here: https://css-tricks.com/restart-css-animation/ (thank you Jacob Gray for posting that reference).

Once I got that working with the reset, I used javascript (yes, this requires javascript) to add the reverse direction when animating back (this could be in a separate class and just add that className).

And, it works. I'm now able to animate in both directions using one keyframes declaration. Pretty snazzy, and drastically minimizes the css code.

window.addEventListener("load", function() {
  var movedOver = false;
  var direction = "";

  document.querySelector("button").addEventListener("click", function() {
    var el = document.querySelector(".one");

    el.classList.remove("do-the-slide");
    el.offsetWidth = el.offsetWidth;

    if (direction === "toRight") {
      direction = "toLeft";
      el.style.animationDirection = "reverse";

    } else {
      direction = "toRight";
      el.style.animationDirection = "";
    }

    el.classList.add("do-the-slide");

  });

});
.container {
  position: absolute;
  perspective: 800px;
  >div {
    position: absolute;
    padding: 20px;
    text-align: center;
    width: 100px;
  }
  >div.do-the-slide {
    animation: moveOver 1s ease-in-out;
    animation-fill-mode: forwards;
  }
  >.one {
    background: red;
  }
}

button {
  margin-top: 100px;
}

@keyframes moveOver {
  from {
    transform: translate3d(0px, 0, 0);
  }
  20% {
    transform: translate3d(-20px, 0, 0);
  }
  80% {
    transform: translate3d(120px, 0, 0);
  }
  to {
    transform: translate3d(100px, 0, 0);
  }
}
<div class="container">
  <div class="one">One</div>
</div>

<button>Clicky</button>

CodePen: http://codepen.io/risingtiger/pen/zqqMpv

like image 166
risingtiger Avatar answered Oct 09 '22 16:10

risingtiger


Maybe you are looking for forwards, but even then, a transition will be needed to make it simple.

p span {
  display: inline-block;
  transition: 1s;
}
p:hover span {
  animation: 1s moveOver forwards;
}
@keyframes moveOver {
  to {
    transform: translateX(100px);
  }
<p><span>span</span>
</p>

I f you want to use a single animation, you will eventually have to deal with paused and steps and i m not even sure that will be easy to handle or possible. I see no fun here :)

for a bounce effect, final value at 50% should be good enough:

p span {
  display: inline-block;
  transition: 1s;
}
p:hover span {
  animation: 2s moveOver infinite;
}
@keyframes moveOver {
  50% {
    transform: translateX(100px);
  }
<p><span>span</span>
</p>
like image 23
G-Cyrillus Avatar answered Oct 09 '22 17:10

G-Cyrillus