How to reverse css animation midway through

To be able to do that I found this:

How would I be able to implement that to the curtains?

https://jsfiddle.net/gLqwtr0z/

Assuming this can even be done, I’m not sure it can.

You are already reversing the curtains when you click the exit button so I don’t understand what you need the know as you have all that in place already.

You need to define what you want to happen explicitly and what method you are going to use to initiate the change in direction?

Are you going to add another button to initiate the change or are you just going to let the curtains open and close by themselves.

What you are asking doesn’t seem to have any logic?

You have disabled the exit button until the curtain is fully open anyway (and vice versa)!

I wanted to know if it was something possible that could be done because I had never seen it done before.

Clicking the animation while it is in the middle of opening, and closing/reversing the curtains from that point.

Here is an example I found that uses transition: https://jsfiddle.net/u43Lokw1/

But, the hover code I found above uses animation to do the same thing.

And I believe hover can be changed to the checkmark method, which means, the hover can work with a click button method also that my code uses.

I can also be wrong about this and that the hover animated code would not be able to work in my code using a click method instead of hover.

I already gave you examples of where transition is used and explained how it is used. You apply transition to the normal state and then when you change something say on hover (or adding a class) the element then transitions to the new value. When the hover is removed it transitions back to the original value. I remember typing in exactly those sentences a few posts ago.

Transitions and animations can do the same things in some simple cases but keyframes are more powerful where complex animations and timings are needed.

The checkbox hack has nothing to do with the question really. It’s just a means of registering a click so that you can start something using css only. You could probably replace 90% of your click actions using the checbox hack but would greatly complicate the html and css.

The hover demo can be converted to click quite easily.

It would be quite complicated for your curtains as the technique requires tow nested animations in order to work so for your curtains you would need 4 animations (2 for each side)/

1 Like

Here’s an example using transition to slide a curtain effect and that can be interrupted easily with a click.

This is your code here that uses transition: https://jsfiddle.net/u6evLot5/

Can the same be done using animation?

The animation code uses these:

animation: spin 3s linear 0s infinite reverse;
animation-play-state: paused;
animation: spin 6s linear 0s infinite normal;

.spiralContainer:hover {
 animation-play-state: running;
}

I’m not sure how the animation code would be added replacing the transition.

I don’t think it can replace it.

The codepen demo you posted relies on a circular animation that is infinite and has no fixed stop or start. If you change it to a linear movement the elements have moved away from each other rather than around each other in a circle.

The demo is also infinite in that it keeps on spinning whereas the curtains have a finite movement and therefore once it reaches the end it stops.

I believe the transition is the only method that achieves this effect properly as transitions go back to their original values with a transition unlike animations. To use css animations for this would require js to work out the percentage position of the element when clicked and then plug that value back into a keyframe so it can work from where it is back to the start etc. That seems rather a lot of work when you can do it with basically one line of css using transition.

2 Likes

If that is the case, would the transition code even be able to replace the animation code in here?

https://jsfiddle.net/gLqwtr0z/

				<div class="sliding-panels">
					<div class="panel-left"></div>
					<div class="panel-right"></div>
				</div>
.container.active .curtain .panel-left {
  animation: curtain1-open 8s forwards 520ms;
}

@keyframes curtain1-open {
  to {
    transform: translateX(calc(-100% - 1px));
  }
}

.container.active .curtain .panel-right {
  animation: curtain2-open 8s forwards 520ms;
}

@keyframes curtain2-open {
  to {
    transform: translateX(calc(100% + 1px));
  }
}

.fadingOut .container.active .curtain .panel-left {
  animation: curtain1-close 8s forwards;
}

@keyframes curtain1-close {
  from {
    transform: translateX(calc(-100% - 1px));
  }

  to {
    transform: translateX(0);
  }
}

.fadingOut .container.active .curtain .panel-right {
  animation: curtain2-close 8s forwards;
}

@keyframes curtain2-close {
  from {
    transform: translateX(calc(100% - 1px));
  }

  to {
    transform: translateX(0);
  }
}

Yes that’s what my demo is already doing :slight_smile:

This https://jsfiddle.net/gLqwtr0z/

.reverse .panel-left {
  transform: translateX(-100%);
}

Replaces all of this?

.container.active .curtain .panel-left {
  animation: curtain1-open 8s forwards 520ms;
}

@keyframes curtain1-open {
  to {
    transform: translateX(calc(-100% - 1px));
  }
}

Is transform: translateX(calc(-100% - 1px)); being added to the reverse code?

Where do all of these classes go?
.container.active .curtain

I’m confused.

When I try to add the transition code, there is no curtain visible, it is just blank.

I would first start with converting this animation code to use transition.

.container.active .curtain .panel-left {
  animation: curtain1-open 8s forwards 520ms;
}

@keyframes curtain1-open {
  to {
    transform: translateX(calc(-100% - 1px));
  }
}

.container.active .curtain .panel-right {
  animation: curtain2-open 8s forwards 520ms;
}

@keyframes curtain2-open {
  to {
    transform: translateX(calc(100% + 1px));
  }
}

.fadingOut .container.active .curtain .panel-left {
  animation: curtain1-close 8s forwards;
}

@keyframes curtain1-close {
  from {
    transform: translateX(calc(-100% - 1px));
  }

  to {
    transform: translateX(0);
  }
}

.fadingOut .container.active .curtain .panel-right {
  animation: curtain2-close 8s forwards;
}

@keyframes curtain2-close {
  from {
    transform: translateX(calc(100% - 1px));
  }

  to {
    transform: translateX(0);
  }
}

My guess would be this: https://jsfiddle.net/ymz2ao6w/

The curtains are visible, but they are not moving.

.container.active .curtain .panel-left {
  transform: curtain1-open translateX(-100%);
}

.container.active .curtain .panel-right {
  transform: curtain2-open translateX(100%);
}

.fadingOut .container.active .curtain .panel-left {
  transform: curtain1-close translateX(-100%);
}

.fadingOut .container.active .curtain .panel-right {
  transform: curtain2-close translateX(100%);
}

That code is wrong as you still have the animation name in there.

.container.active .curtain .panel-left {
  transform: translateX(-100%);
}

.container.active .curtain .panel-right {
  transform: translateX(100%);
}

.fadingOut .container.active .curtain .panel-left {
  transform:  translateX(-100%);
}

.fadingOut .container.active .curtain .panel-right {
  transform:  translateX(100%);
}

However it seems that the issue lies in the fact that the container is display:none to start with so there is nothing for the transition to transition from. When you add the active class only then does the container get display:block and as the new translate is added the element just starts directly at the new position.

The element never had a translate starting at zero because it was display:none. It only becomes an element once it is display:block and therefore there is no transition from a previous state.

You can see the proof in this codepen if you uncomment the css code at the bottom and then try to click the box.

To get this to work would require not using display:none to hide the containers that hold the curtains. This would seem to be a lot of work unless you really want this functionality.

Also if you want the open and close clicking behaviour on the curtain you would need to change the way you exit as you have a timed exit that could be interrupted if someone clicked to open the curtains again.

There is a lot of logic that needs to be defined before coding can take place.:slight_smile:

I can do without the curtains opening and closing.

Is there a way for transition to still work?

I found this older code where transition works with the curtains.

https://jsfiddle.net/zhkrgtd1/

Maybe it can’t be done and that was the reason why it was changed to animation.

Curtains will not open again, only close when the exit button is clicked.

But even then, transition still might not be able to work.

Yes if we remove the display:none and use clip to hide everything then the transition will work and you can still do the click to open and close.

This is a rough proof oc concept demo as I don’t know which version this is and I have fiddled with the other transitions before I added the new code so just refer to the curtain animation changes.

I added some js at the top of the js panel so that you click the curtains before they have closed to open them again.

1 Like

I think we can agree that using animation is the much preferred method way of doing this.

Thank you for showing me an example.

I see the reverse working at this link here: https://jsfiddle.net/764fuvpj/3/

This is deleted not needed now: It wasn’t needed in your code either.

const curtain = document.querySelector(".sliding-panels");

curtain.addEventListener("click", reverseAnimation);
function reverseAnimation() {
  curtain.classList.toggle("reverse");
}

This is added back in:

.hide {
display:none;
}

Is this not needed then?.

hide {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
  max-width:none;
  min-width:none;
}

And doing this:

.container.active .thePlay {
display:none;
}

Instead of this:

.container.active .thePlay {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
  max-width: none;
  min-width: 0;
}

This one wont work in the code using display:none;

Could something else be used there instead to replace all of that?

Like how it was done with the other ones?

.outer:not(.isOpen) .inner-container {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
  max-width: none;
  min-width: 0;
}

This works in the code but then the buttons are out of order then.

Seen here: https://jsfiddle.net/764fuvpj/4/

.outer:not(.isOpen) .inner-container {
visibility:hidden;
}

Yes it was.

If you click the curtains they reverse direction and you can keep clicking and reversing direction until they are fully open of course. After all that was what this thread was about and you didn’t check?

I wasn’t sure where you were adding the hide class dynamically and if it was added to a parent of the curtains then it would break the transition. If you are only adding it to the play buttons then it won’t affect the curtains so you can just use display:none on them.

No you can’t use visibility as it does not remove the elements from the flow and will affect the layout.

You don’t seem to understand the concept very well. When you use display:none the element is gone completely and has no affect on anything and can’t be transitioned. Using the clip method you can make the element appear to be gone but it is still there but just so small you can’t see it. This allows all transitions to work when the clip is removed. It also allows screen readers to see it and make sense of the structure.

It’s called ‘visually hiding’ something as in essence you don’t want to hide content but you just want to see it in a certain order. That’s why on dropdown menus it is preferable not to use display:none but to hide the element off screen or with a method such as clip.

The clip method is the most semantic because both display:none and visibility:hidden can mean the elements are not really accessible.

2 Likes

Removed from code:

https://jsfiddle.net/h810f7xg/

/.container.active .curtain .reverse .panel-left,
.container.active .curtain .reverse .panel-right {
transform: translateX(0);
}
/

/*
curtain.addEventListener(“click”, reverseAnimation);
function reverseAnimation() {
curtain.classList.toggle(“reverse”);
}*/

Your code here with that added: https://jsfiddle.net/d3q2uc1w/1/

Only change I made was, exit but appears on the screen right away.

I don’t see a difference?

Yes both are different and you are not checking the very thing that you asked about in this thread!

How to reverse css animation midway through

I don’t think I can say it any clearer.

  1. Click the play button

  2. When the next page opens the curtains start to close.

  3. Quickly click on the actual curtain before it has opened fully or it will be gone.

  4. The curtain reverses direction - (this is what you asked for).

  5. Click on it again and it changes direction again

  6. Click on it all night until you have had enough of seeing it going backwards and forwards.

In your first demo nothing happens when you click on the curtain.

1 Like

Yes, now I see the difference in your code.

I think I will stick with using animation for the curtains.

Also, thank you for showing me this:

You mentioned it in another post, but I did it wrong.

body {
  background: #353198;
  animation: fadeInButtons 0s ease 0s forwards;
}

@keyframes fadeInButtons {
  0% {
    opacity: 0;
    pointer-events: none;
  }

  99% {
    pointer-events: none;
  }

  100% {
    opacity: 1;
    pointer-events: initial;
  }
}

.thePlay circle {
  animation: fadeInButtons 0s ease 0s forwards;
  pointer-events: none;
}

body.initial-fade {
  animation: initial-fade 0s ease forwards;
}

@keyframes initial-fade {
  to {
    opacity: 0;
  }
}

.initial-fade .thePlay,
.initial-fade .thePlay * {
  pointer-events: none !important;
}