Toggling a CSS3 animation on click

2019-06-22 10:04发布

What is the best way to alternate the direction of a CSS3 animation on click without javascript?

I've been exploring checkbox hacks lately and trying to figure out a way to have only one set of keyframes instead of two sets for one going forward and one to come back. Is this possible? Or is there a way to do it with one set?

For instance I have the following keyframes:

@keyframes moveIt {
  0%   { 
    transform: translateX(0);
    width: $size;
  }
  50%  {
    width: $size*1.2;
  }
  100% {
    transform: translateX(50px);
    width: $size;
  }
}
@keyframes moveItBack {
  100%   { 
    transform: translateX(0);
    width: $size;
  }
  50%  {
    width: $size*1.2;
  }
  0% {
    transform: translateX(50px);
    width: $size;
  }
}

Any way to reduce this to only the first set? Then when coming back start from 100% and go back to 0%?

Here is an example of what I am trying to accomplish this on.

2条回答
何必那么认真
2楼-- · 2019-06-22 10:16

CSS is not really meant to do something like this but there are some work-arounds

Optimally we could do something like the following because it makes sense logically

.bubble {
  ...
  animation: moveIt .25s forwards ease-out;
}
input[type=checkbox]:checked ~ .bubble {
  animation: moveIt .25s backwards ease-out;
}

However, you cannot reset or change to a different animation using pure CSS[1]. This is because elements are only allowed to have one animation each. You can reset it in javascript by using setTimeout or cloning the element, but I assume you're trying to avoid that.

Thus, you're left with two options. The first is to ditch the change in size and just toggle the translateX like so:

.bubble {
  ...
  transition: all .25s ease-out;
}
input[type=checkbox]:checked ~ .bubble {
  transform: translateX(50px);
}

The other option to retain the change in size is to do something a bit more involved. You can essentially fake the change of size by using pseudo elements. By toggling the animation of both opposite from each other, you can make the whole element look like it pulses each time. Demo

.bubble {
  ...
  transition: all .25s ease-out;
}
.bubble:after, .bubble:before {
  content:''; 
  position:absolute;
  width:100%; height:100%;
  background:inherit;
  border-radius:inherit;
  animation:'';
}
.bubble:before { animation:size .25s ease-out; }
input[type=checkbox]:checked ~ .bubble:before { animation:''; }
input[type=checkbox]:checked ~ .bubble {
  transform: translateX(50px);
}
input[type=checkbox]:checked ~ .bubble:after {
  animation:size .25s ease-out;
}
@keyframes size {
  50% { transform:scale(1.2); }
}

I hope it makes sense!

[1]: As seen in the second option, it is possible, it just requires a state of removing the past animation. Sadly something like animation:''; animation:moveIt .25s backwards ease-out; does not reset it

查看更多
干净又极端
3楼-- · 2019-06-22 10:26

This should do the same, just double the duration.

@keyframes moveIt {
  0%   { 
    transform: translateX(0);
    width: $size;
  }
  25% {
    width: $size*1.2;
  }
  50%  {
    transform: translateX(50px);
  }
  75% {
    width: $size*1.2;
  }
  100% {
    transform: translateX(0);
    width: $size;
  }
}
查看更多
登录 后发表回答