Home > front end >  How to stack keyframes in CSS animation programmatically
How to stack keyframes in CSS animation programmatically

Time:01-29

I am trying to stack CSS keyframes (animation-delay) on the following and I am not sure how to do this programmatically?

        .r1 {
          animation-name: move1;
          animation-delay: 0.5s;      
          animation-duration: 1s;
          animation-iteration-count: 1;
          animation-timing-function: ease-in;
          animation-direction: normal;
          animation-fill-mode: forwards;
        }
 
        .r2 {
          animation-name: move1;
          animation-delay: 1.5s;      
          animation-duration: 1s;
          animation-iteration-count: 1;
          animation-timing-function: ease-in;
          animation-direction: normal;
          animation-fill-mode: forwards;
        }
             .r3 {
          animation-name: move1;
          animation-delay: 2.5s;      
          animation-duration: 1s;
          animation-iteration-count: 1;
          animation-timing-function: ease-in;
          animation-direction: normal;
          animation-fill-mode: forwards;
        }
 
        @keyframes move1 {
          to {
            transform: translateX(200px);
          }  
        }
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect  x="10" y="20" width="100" height="100" fill="red"/>
    <rect  x="10" y="130" width="100" height="100" fill="green"/>
    <rect  x="10" y="240" width="100" height="100" fill="blue"/>
</svg>

The animation-duration is hardcoded for each class and the animation-delay is hardcoded for the first class, i.e.r1.

How can I pass on the delay for r2 and r3, such as

r2 delay= r1 delay r1 duration->0.5 1=1.5s

and

r3 delay= r2 delay r2 duration ->1.5 1=2.5s

Is there anything in javascript that gives animation-duration by class?

I tried doing this by Element.getAnimations() but I am not sure if there is anything that gives animation duration by class.

I don't want to do this manually as I have a lot of class in the svg.

Thank you in advance.

CodePudding user response:

Set r class for your rects and I think this can help you:

const blocks = document.querySelectorAll('svg rect');

for (let i = 1; i<blocks.length; i  ) {
    const element = blocks[i];
  const prevElementStyles = getComputedStyle(blocks[i-1]);

  
  element.style.animationDelay = `${parseFloat(prevElementStyles.animationDelay)   parseFloat(prevElementStyles.animationDuration)}s`;
}

r class:

.r {
  animation-name: move1;
  animation-delay: 0.5s;      
  animation-duration: 1s;
  animation-iteration-count: 1;
  animation-timing-function: ease-in;
  animation-direction: normal;
  animation-fill-mode: forwards;
}

<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 720">
<rect  x="10" y="20" width="100" height="100" fill="red"/>
    <rect  x="10" y="130" width="100" height="100" fill="green"/>
    <rect  x="10" y="240" width="100" height="100" fill="blue"/>
</svg>

CodePudding user response:

Animation chaining: use the event animationend

You can chain CSS animations by using a listener on this event. It will be triggered when an animation on an element has been completed (including animation delays). Alternatively, if you use transitions, you need to use the transitionend event.

Basic workflow

Extract the animation properties into a separate class, e.g. .animation.

#firstEl.animation {
  // your animation properties
}
#secondEl.animation {
  // your animation properties
}
// etc
const firstEl = document.getElementById('#firstEl');
const secondEl = document.getElementById('#secondEl');
const thirdEl = document.getElementById('#thirdEl');

firstEl.classList.add('animation');
firstEl.addEventListener('animationend', () => {
  // start the 2nd animation
  secondEl.classList.add('animation');
});
secondEl.addEventListener('animationend', () => {
  // start the 3rd animation
  thirdEl.classList.add('animation');
});
// etc

Example

Here is an example with chained animations (from the docs):

const animation = document.querySelector('p.animation');
const animationEventLog = document.querySelector('.animation-example>.event-log');
const applyAnimation = document.querySelector('.animation-example>button.activate');
let iterationCount = 0;

animation.addEventListener('animationstart', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation started' `;
});

animation.addEventListener('animationiteration', () => {
  iterationCount  ;
  animationEventLog.textContent = `${animationEventLog.textContent}'animation iterations: ${iterationCount}' `;
});

animation.addEventListener('animationend', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation ended'`;
  animation.classList.remove('active');
  applyAnimation.textContent = "Activate animation";
});

animation.addEventListener('animationcancel', () => {
  animationEventLog.textContent = `${animationEventLog.textContent}'animation canceled'`;
});

applyAnimation.addEventListener('click', () => {
  animation.classList.toggle('active');
  animationEventLog.textContent = '';
  iterationCount = 0;
  let active = animation.classList.contains('active');
  if (active) {
    applyAnimation.textContent = "Cancel animation";
  } else {
    applyAnimation.textContent = "Activate animation";
  }
});
.container {
  height: 3rem;
}

.event-log {
  width: 25rem;
  height: 2rem;
  border: 1px solid black;
  margin: .2rem;
  padding: .2rem;
}

.animation.active {
  animation-duration: 2s;
  animation-name: slidein;
  animation-iteration-count: 2;
}

@keyframes slidein {
  from {
    margin-left: 100%;
    width: 300%;
  }
  to {
    margin-left: 0%;
    width: 100%;
  }
}
<div >
  <div >
    <p >You chose a cold night to visit our planet.</p>
  </div>
  <button  type="button">Activate animation</button>
  <div ></div>
</div>

  •  Tags:  
  • Related