Is there a way to use JavaScript to determine our current position in a CSS Keyframe animation based on a percentage?

After some thought, I realized that it's possible to detect when a CSS animation starts, finishes, or repeats by using the animationstart, animationiteration, and animationend events. For example:

document.getElementById('identifier')
        .addEventListener("animationstart", function(){
          // do something...
        });

But then I started wondering, is there a way to determine where we are within a CSS animation? Like, how can I listen for when we reach the 50% mark of a keyframe animation, as shown below:

<!DOCTYPE html>
<html>
<head>
<style>
#animateDiv {
    width: 100px;
    height: 100px;
    background-color: red;
    position: relative;
    animation-name: example;
    animation-duration: 4s;
}

@keyframes example {
    0%   {background-color:red; left:0px; top:0px;}
    25%  {background-color:yellow; left:200px; top:0px;}
    50%  {background-color:blue; left:200px; top:200px;}
    75%  {background-color:green; left:0px; top:200px;}
    100% {background-color:red; left:0px; top:0px;}
}
</style>
</head>
<body>
<div id="animateDiv"></div>
<script>
// What should I do here to listen for the event at 50% of the keyframes?
document.getElementById('animateDiv').addEventListener('animation at 50%?', function() {
 console.log('got it');
})
</script>
</body>
</html>

Answer №1

Is it possible to pinpoint the exact keyframe in a CSS animation? While that may be challenging, you can apply mathematical calculations, as recommended by our friend Paulie_D.

In your scenario, with the animation lasting 4 seconds, the keyframe at 50% occurs after 2 seconds:

//......
//commence animation....
setTimeout(function(){
      //Insert your code here
}, 2000); //2-second delay, based on the 4-second animation length;

An alternative approach involves utilizing jQuery (if available):

$("#animated_element").bind("half_animation", function(){
      //Customize your content here
});
//.........
//Initiate the animation...
setTimeout(function()
{
     $("#animated_element").trigger("half_animation");
}, 2000);

Or consider this method:

$("#animated_element").bind("half_animation", function(){
      once = 0;
      setTimeout(function()
      {
           //Implement your actions....
      }, 2000)
});
//........
//Start of the animation
$("#animated_element").trigger("half_animation");

Answer №2

Here's my perspective.

  1. Retrieve the duration of the animation.
  2. Add some mathematical calculations as suggested by Vini.
  3. setTimeout()

Code snippet:

const executeAtKeyframe = (element, keyframe, action) => {
  const animationDuration = window.getComputedStyle(element).animationDuration;
  // The animationDuration is returned as a string, e.g., "5s" or "500ms", so we need to parse it
  // Convert seconds to milliseconds if necessary
  let animationKeyframe;
  if (animationDuration.replace(/[0-9]/g, '') === "s") {
    animationKeyframe = parseInt(animationDuration) * keyframe * 1000;
  } else {
    animationKeyframe = parseInt(animationDuration) * keyframe;
  }

  const performAction = (e) => {
    setTimeout(() => {
      console.log(`Function "${action.name}" will run at ${keyframe*100}% keyframe`);
      action();
    }, animationKeyframe);
  }
  element.addEventListener("animationstart", performAction); 
  // You can also use "animationiteration" depending on your requirements
}

Implementation:

const targetElement = document.querySelector("#targetElement");
const specifiedKeyframe = 0.5; // at 50% keyframe
const actionCallback = () => {
  // Perform actions here...
};
executeAtKeyframe(targetElement, specifiedKeyframe, actionCallback);

Answer №3

Just like Vini mentioned, you have the opportunity to customize this according to your needs. Feel free to modify the "animation-play-state:" property with any function that suits your requirements.

//Pause animation at a specific percentage, for example: pauseAnimationAt("myElement", 33, 10)
    function pauseAnimationAt(elementId, percentage, duration){
      var calculatedPercentage = percentage / duration * 1000;
      function pauseCurrentAnimation(){
        setTimeout(function(){ document.getElementById(elementId).style="animation-play-state: paused"; }, calculatedPercentage);
      }
      document.getElementById(elementId).addEventListener("animationstart", pauseCurrentAnimation());
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Could you provide me with some information regarding the relationship between screen resolution and screen size?

When checking my website on different screen resolutions, I rely on a tool called Screenfly from quirktools.com. While using this tool, I came across an interesting feature - the display icon in the top left corner with a dropdown menu showing resolution ...

Transform the information sent from the server into a user-friendly interface using typescript on the frontend

Received data from the backend looks like this: id: number; user_id: number; car_brand: string; car_model: string; vin: string; equipment: string; reg_number: string; car_mileage: number; car_year: string; Meanwhile, the interface in the ...

Utilizing Thymeleaf With JavaScript in Spring Boot: A Comprehensive Guide

Within my Spring Boot project, I am attempting to utilize Thymeleaf for injecting data into a JavaScript file that undergoes preprocessing with babel via WebPack. The Thymeleaf setup is outlined as follows: @Bean public SpringTemplateEngine templateEngine ...

Embedding a Javascript variable within another variable

I have created a variable out of a cookie. var exiturl = readCookie("exiturl"); Now, I have an exit popup script that usually redirects to . Here is how the script looks: var exitsplashpage = 'http://myexitpage.com' ; I would like to replace ...

What is causing my button to act in this way?

Initially, the website redirects to an undefined URL and then to test.com. I am looking for a way to implement a redirection sequence from to and finally to <head> <script type="text/javascript"> <!-- function popup(url ...

Tips for retrieving data from a JSON array

I have a JSON object that looks like this: var obj={ "address":{ "addlin1":"", "addlin2":"" }, "name":"sam", "score":[{"maths":"ten", "science":"two", "pass":false }] } Now, when I attempt to m ...

Is it feasible to choose the component generated by this element?

My current dilemma involves a component that renders a form, however, it also has its own form "catcher". var FormUpload = React.createClass({ submit : function(){ var formdata =new FormData(); ...

How do I handle the error "Uncaught TypeError: Cannot read property 'func' of undefined in React JS

Hey there, I've encountered an issue while setting up a date picker on my project. I tried using these resources: https://github.com/Eonasdan/bootstrap-datetimepicker Would appreciate any help! https://codesandbox.io/s/18941xp52l render() { ...

Use vanilla JavaScript to send an AJAX request to a Django view

I'm attempting to make a GET AJAX request to a Django view using vanilla JS. Despite passing is_ajax(), I am having trouble properly retrieving the request object. Below is my JavaScript code. Whether with or without JSON.stringify(data), it does not ...

There was a problem uploading the Feed document using amazon-sp-api: Invalid initialization vector encountered

I'm encountering an issue while attempting to upload a Feed document to Amazon using the createFeedDocument operation of the Selling Partner API. Following the API call, I received a response object that includes the feedDocumentId, url, and encryptio ...

Searching through an array of objects in MongoDB can be accomplished by using the appropriate query

Consider the MongoDB collection 'users' with the following document: { _id: 1, name: { first: 'John', last: 'Backus' }, birth: new Date('Dec 03, 1924'), death: new Date('Mar 1 ...

Best practices for organizing an array of objects in JavaScript

I have an array of objects with nested arrays inside, and I need to restructure it according to my API requirements. [{ containerId: 'c12', containerNumber: '4321dkjkfdj', goods: [{ w ...

What is the best way to include multiple hostnames and pathnames in a Next.js configuration file for image assets?

My attempt to import multiple images from different hostnames for next/image is not working as expected. In my next.config.js, I have tried the following setup: module.exports = { images: { remotePatterns: [ { protocol: 'https&apos ...

Exploring the best practices for loading state from local storage in VueJS/NuxtJS by leveraging the "useLocalStorage" utility

When attempting to utilize useLocalStorage from pinia, I am encountering an issue where the data in the store's state is not fetched from local storage and instead defaults to the default value. Below is the code snippet from my store method: import ...

Identify support for the :first-child pseudo-class

Is there a way to determine with JavaScript whether the browser is compatible with the CSS :first-child selector? ...

Transferring information through AJAX and fetching through PHP

Below is my current AJAX code setup: optionScope.data().stage = 'b'; $.ajax({ url: "functions/contact.php", type: "post", data: {'stage': optionScope.data().stage}, success: function(data, status) { ...

Access the file using NodeJS and SailsJS for download

I am working on creating an API to enable the download of a static file named test.js. Upon testing the API using Postman, I noticed that instead of initiating a download process, it simply displays the content of the file. Is this behavior acceptable? a ...

It is not possible to import node_modules within an electron worker process

Question I'm currently experimenting with using web workers within an Electron application. I have been successful in creating the worker process from the renderer process, but I am encountering a crash when attempting to use require('some_modul ...

Tips for effectively utilizing v-if, v-else within a v-for loop in your Vuejs application

<template> <div> <div v-for="box in boxes" :key="box.id"> <BaseAccordian> <template v-slot:title>{{ box.name }}</template> <template v-slot:content> <div v-for="paint in pai ...

Update the CSS property according to the selected list item in the slider using Glider JS

Looking to dynamically change the background image in CSS based on the active slide value in Glider.js Here is the CSS: html { background-image: url("https://images.unsplash.com/photo-1496518908709-02b67989c265?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEy ...