CSS动画 - 如何使用一个关键帧声明切换方向

时间:2016-03-09 18:29:08

标签: css animation

我希望在单击按钮时将div设置为右边的动画,然后在单击相同的按钮时再次向左设置动画。我想只使用一个关键帧声明。这可以通过交换类来实现吗?

我已经在CodePen中尝试了这个,但不幸的是,div在第一个动画后重新拍摄,然后拒绝第二次动画。

我没有使用css过渡,因为我希望能够使用css动画的功能,如弹跳效果。

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

HTML:

<div class="container">
  <div class="one">One</div>
<div>

<button>Clicky</button>

SCSS:

.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);
  }
}

JS:

    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");         
        }

      });

    });

3 个答案:

答案 0 :(得分:1)

也许您正在寻找forwards,但即使这样,也需要进行转换才能简化。

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

如果你想使用单个动画,你最终将不得不处理暂停和步骤,我甚至不确定它是否易于处理或可能。我觉得这里没什么好玩的。)

对于反弹效果,50%的最终值应该足够好:

&#13;
&#13;
p span {
  display: inline-block;
  transition: 1s;
}
p:hover span {
  animation: 2s moveOver infinite;
}
@keyframes moveOver {
  50% {
    transform: translateX(100px);
  }
&#13;
<p><span>span</span>
</p>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

好吧,所以在摆弄了一段时间之后,我想出了一个我认为可以接受的解决方案,使用一个关键帧声明来驱动两个动画方向。关键是迫使浏览器基本上通过重绘重置,如下所述:https://css-tricks.com/restart-css-animation/(感谢Jacob Gray发布该引用)。

一旦我使用了重置,我使用javascript(是的,这需要javascript)在动画回来时添加反向(这可能是在一个单独的类中,只是添加该className)。

而且,它有效。我现在可以使用一个关键帧声明在两个方向上制作动画。非常时髦,并大大减少了CSS代码。

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

HTML:

<div class="container">
  <div class="one">One</div>
</div> 

<button>Clicky</button>

CSS:

.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);
  }
}

JS:

    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");   

      });

    });

答案 2 :(得分:-2)

我根据这篇文章和此处的css-tricks文章codepen

HTML

<h2>Single keyframe-track burger collection</h2>
<p>(each span uses only one track to play for- and backwards)</p>

<div class="wrapper">
  <div class="cell">
    <h3>Default</h3>
    <div>
      <button class="burger">
        <span class="burger__bar"></span>
        <span class="burger__bar"></span>
        <span class="burger__bar"></span>
      </button> 
    </div>
  </div>

  <div class="cell">
    <h3>Merge</h3>
    <div>
      <button class="burger burger--merge">
        <span class="burger__bar"></span>
        <span class="burger__bar"></span>
        <span class="burger__bar"></span>
      </button> 
    </div>
  </div>

  <div class="cell">
    <h3>Rotate</h3>
    <div>
      <button class="burger burger--rotate">
        <span class="burger__bar"></span>
        <span class="burger__bar"></span>
        <span class="burger__bar"></span>
      </button> 
    </div>
  </div>

  <div class="cell">
    <h3>Spin</h3>
    <div>
      <button class="burger burger--spin">
        <span class="burger__bar"></span>
        <span class="burger__bar"></span>
        <span class="burger__bar"></span>
      </button> 
    </div>
  </div>

</div>

CSS

body {
  position: relative;
  padding: 0;
  margin: 0;
  width: 100%;
  height: 100vh;
  background: radial-gradient(#5E802B, #2F4016);
  font-family: sans-serif;
  text-align: center;
  h2,
  h3,
  p {
    color: rgb(255, 255, 255);
  }
}
.wrapper {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
}

.cell {
  flex-grow: 1;
  flex-basis: 50%;
  margin: 0 20px;
  display: flex;
  flex-direction: column;

  div {
    margin-top: auto;
  }
}
/****************
* Burger Styles *
*****************/
.burger {
  position: relative;
  width: 60px;
  height: 60px;
  padding: 0;
  border: none;
  background-color: transparent;

  &__bar {
    height: 10%;
    border-radius: 2px;
    width: 80%;
    background-color: white;
    display: block;
    position: absolute;
    left: 50%;
    animation-timing-function: ease-in-out;
    animation-play-state: paused;
    animation-duration: .4s;
    animation-fill-mode: both;

    &:nth-child(1) {
      top: 25%;
      transform: translate(-50%, 0%);
    }
    &:nth-child(2) {
      top: 50%;
      transform: translate(-50%, -50%);
    }
    &:nth-child(3) {
      bottom: 25%;
      transform: translate(-50%, 0%);
    }
  }

  &.close .burger__bar {
    animation-direction: reverse;
  }
  &.open .burger__bar {
    animation-direction: normal;
  }
  // default
  &.animate .burger__bar { 
    animation-play-state: running;
    &:nth-child(1) {
      animation-name: default-top;
    }
    &:nth-child(2) {
      animation-name: default-middle;
    }
    &:nth-child(3) {
      animation-name: default-bottom;
    }
  }

  &--merge.animate .burger__bar {
    animation-duration: .6s;
    animation-timing-function: ease;
    &:nth-child(1) {
      animation-name: merge-top;
    }
    &:nth-child(2) {
      animation-name: merge-middle;
    }
    &:nth-child(3) {
      animation-name: merge-bottom;
    }
  }

  &--rotate.animate .burger__bar {
    &:nth-child(1) {
      animation-name: rotate-top;
    }
    &:nth-child(2) {
      animation-name: rotate-middle;
    }
    &:nth-child(3) {
      animation-name: rotate-bottom;
    }
  }

  &--spin.animate .burger__bar {
    animation-duration: 1s;
    animation-timing-function: ease;

    &:nth-child(1) {
      animation-name: spin-top;
    }
    &:nth-child(2) {
      animation-name: spin-middle;
    }
    &:nth-child(3) {
      animation-name: spin-bottom;
    }
  }
}

/*__________________
       DEFAULT
____________________*/
@keyframes default-top {
  50%  {
    top:50%;
    transform: translate(-50%, -50%) rotate(0);
  }
  100% {
    top:50%;
    transform: translate(-50%, -50%) rotate(-45deg);
  }
}
@keyframes default-middle {
  50%, 100% {visibility:hidden;}
}
@keyframes default-bottom {
  0%   {}
  25%  {}
  50%  {
    bottom:50%;
    transform: translate(-50%, -50%) rotate(0deg);
  }
  100% {
    bottom:50%;
    transform: translate(-50%, 50%) rotate(45deg);
  }
}
/*__________________
       MERGE
____________________*/
@keyframes merge-top {
  20%  {
    top:50%;
    transform: translate(-50%, -50%) rotate(0) scale(1, 1);
    //width: 100%;
  }
  50%  {
    transform: translate(-50%, -50%) rotate(0) scale(0.2, 1);
    //width: 20%;
  }
  60% {
    transform: translate(-50%, -50%) rotate(-45deg) scale(0.2, 1);
    //width: 20%;
  }
  100% {
    top:50%;
    transform: translate(-50%, -50%) rotate(-45deg) scale(1, 1);
    //width: 100%;
  }
}
@keyframes merge-middle {
  50%  {
    transform: translate(-50%, -50%) scale(0, 1);
  }
  51%{visibility:hidden;}
  99% {
    transform: translate(-50%, -50%) scale(0, 1);
  }
  100% {visibility:hidden;}
}
@keyframes merge-bottom {
  20%  {
    bottom:40%;
    transform: translate(-50%, -50%) rotate(0deg) scale(1, 1);
  }
  50%  {
    transform: translate(-50%, -50%) rotate(0deg) scale(0.2, 1);
  }
  60% {
    transform: translate(-50%, -50%) rotate(45deg) scale(0.2, 1);
  }
  100% {
    bottom:40%;
    transform: translate(-50%, -50%) rotate(45deg) scale(1, 1);
  }
}
/*__________________
       ROTATE
____________________*/
@keyframes rotate-top {
  50%  {
    top:50%;
    transform: translate(-50%, -50%) rotate(0deg);
  }
  100% {
    top:50%;
    transform: translate(-50%, -50%) rotate(45deg);
  }
}
@keyframes rotate-middle {
  50%  {transform: translate(-50%, -50%) rotate(0deg);}
  100% {transform: translate(-50%, -50%) rotate(135deg);}
}
@keyframes rotate-bottom {
  50%  {
    bottom:50%;
    transform: translate(-50%, 50%) rotate(0deg);
  }
  100% {
    bottom:50%;
    transform: translate(-50%, 50%) rotate(45deg);
  }
}

/*__________________
       SPIN
____________________*/
@keyframes spin-top {
  50%  {
    top:50%;
    transform: translate(-50%, -50%) rotate(0deg);
  }
  75% {
    transform: translate(-50%, -50%) rotate(360deg);
  }
  100% {
    top:50%;
    transform: translate(-50%, -50%) rotate(315deg);
  }
}
@keyframes spin-middle {
   50%  {visibility:hidden;}
  100% {visibility:hidden;}
}
@keyframes spin-bottom {
  50%  {
    bottom:50%;
    transform: translate(-50%, 50%) rotate(0deg);
  }
  75% {
    transform: translate(-50%, 50%) rotate(450deg);
  }
  100% {
    bottom:50%;
    transform: translate(-50%, 50%) rotate(405deg);
  }
}

JavaScript

burgers = document.querySelectorAll('.burger');
for (let i = 0; i < burgers.length; i++) {
     burgers[i].addEventListener("click", function(){
       this.classList.remove("animate");

       var bars = this.querySelectorAll('.burger__bar');
       for (let i = 0; i < bars.length; i++) {
         // Reset span animations - https://css-tricks.com/restart-css-animation/
         void bars[i].offsetWidth;
       }

       if (this.classList.contains("open")){
         this.classList.remove("open");
         this.classList.add("close");
       } else {
         this.classList.remove("close");
         this.classList.add("open");
       }  
       this.classList.add("animate");
    });
};