Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How can I keep element at last state of CSS animation?

I have a page with a lot of interactivity going on. Clicking a button here changes the text and image over there… that kind of stuff. Just about everything is controlled by click handlers adding or removing CSS classNames to show or hide the appropriate content. Almost all of the animation is achieved with CSS transitions. Pretty straight forward.

But I have one element that requires a keyframe animation. Its default state is to be hidden until it’s time for it to enter the UI… at which point it needs to have this CSS keyframe animation applied and stay in the last state the animation had it in.

For the sake of this example, let’s just say that when Block A becomes visible (by clicking the button), the element in question, Block A1, needs to fade in (remember in my actual use case, the animation is more complicated and can’t be achieved using transitions… it requires a keyframe animation) and then remain with the properties it had in the last frame of the animation: in this case opacity: 1 after the animation runs.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Right now, the only way I’m able to do this is to use javascript to set the opacity after the animation runs. This works but I can see it getting really messy/complicated when elements now have a style attribute overriding the styles set in the CSS rulesets. You can see this start to happen when you click the button again to hide the block and then AGAIN to show it… Block A1 is still set to opacity: 1 so the animation ha no effect after the 1st time around.

Is there a better way to do this?

const $btn = document.querySelector('button');
const $block = document.querySelector('.block-a');
const $blocka1 = document.querySelector('.block-a-1');

$btn.addEventListener('click', function() {
  $block.classList.toggle("is-visible")
})

$blocka1.addEventListener('animationend', function() {
  console.log('done');
  this.style.opacity = 1;
})
body {
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

button {
  font-size: 32px;
  margin-bottom: 24px;
  cursor: pointer;
}

.block-a {
  width: 25vw;
  height: 50vh;
  background-color: red;
  padding: 20px;
  color: #fff;
  transform: translateY(150%);
  transition: all .25s linear;
}

.block-a.is-visible {
  transform: translateY(0);
  transition: all .1s ease-in;
}

.block-a-1 {
  font-size: 32px;
  font-weight: bold;
  color: white;
  background-color: blue;
  padding: 10px;
  opacity: 0;
}

.block-a.is-visible .block-a-1 {
  animation: fadeIn 2s linear 2s;
}

@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
<button>Do Block 1</button>

<div class="block-a">
  <span class="block-a-1">Block A-1</span>
  <h1>Block A</h1>
</div>

>Solution :

You can maintain the last animation frame using:

animation-fill-mode:forwards;

https://developer.mozilla.org/en-US/docs/Web/CSS/animation-fill-mode

const $btn = document.querySelector('button');
const $block = document.querySelector('.block-a');

$btn.addEventListener('click', function() {
  $block.classList.toggle("is-visible")
})
body {
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

button {
  font-size: 32px;
  margin-bottom: 24px;
  cursor: pointer;
}

.block-a {
  width: 25vw;
  height: 50vh;
  background-color: red;
  padding: 20px;
  color: #fff;
  transform: translateY(150%);
  transition: all .25s linear;
}

.block-a.is-visible {
  transform: translateY(0);
  transition: all .1s ease-in;
}

.block-a-1 {
  font-size: 32px;
  font-weight: bold;
  color: white;
  background-color: blue;
  padding: 10px;
  opacity: 0;
}

.block-a.is-visible .block-a-1 {
  animation: fadeIn 2s linear 2s;
  animation-fill-mode:forwards;
}

@keyframes fadeIn {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
<button>Do Block 1</button>
<div class="block-a">
  <span class="block-a-1">Block A-1</span>
  <h1>Block A</h1>
</div>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading