skip to Main Content

I want to make a css animation editor tool using css keyframes animations.
The idea is to have a timeline to play and preview a css animation, and settle keyframes on.

The problematic is for the animation preview, i have to interpolate the style of my html element at a specific timepoint between two keyframes. It can be calculated in js for simple value ( such as top position number for example ), but in some scenario it can be tricky to interpolate some css properties in js ( for example border-radius, how to interpolate a value from "50% 20% 10% 10%" to "20% / 10%" ??? )
One idea to solve that is to play and interpret css keyframe animation only at a specific keyframe.
But it seems to be complicated to play only specific range of a css animation. I know there are the animation-range, animation-range-start and animation-range-end css properties, but these properties are still experimental and does not seems to work in my scenario.

So currently i have no idea how to solve that in the best way. The js interpolation way is doable but complex for specific scenario as explained (how to blend a css border radius style value between border-radius: 10% 30% 50% 70%; and border-radius: 10% / 50%; ?), and the css way is complex to solve in a proper way.

This is what i tried with css

<head>
    <style>
        @keyframes colorAnim {
            0% {
                color: black;
            }

            50% {
                color: red;
            }

            100% {
                color: green;
            }
        }

        .animated-element-with-offset {
            animation: colorAnim 100ms infinite;
            animation-play-state: paused;
        }
    </style>
</head>

<body>
    <div class="animated-element-with-offset" id="some-element-you-want-to-animate">
        Text Color Animation frame #50: Color expected is red
    </div>

    <button onclick="interpretAndPauseAnimation(50)">Interpret and Pause Animation at 50%</button>

    <script>
        const element = document.getElementById("some-element-you-want-to-animate");
        let start, previousTimeStamp;

        let duration = 100;
        let endDuration = 49;

        let done = false;

        function step(timeStamp) {
            if (start === undefined) {
                start = timeStamp;
            }
            const elapsed = timeStamp - start;

            if (previousTimeStamp !== timeStamp) {
                if (elapsed > duration * (endDuration / 100)) {
                    done = true;
                    element.style.animationPlayState = 'paused';
                } else {
                    element.style.animationPlayState = 'running';
                }
            }

            if (elapsed < duration) {
                // Stop the animation after 2 seconds
                previousTimeStamp = timeStamp;
                if (!done) {
                    window.requestAnimationFrame(step);
                }
            }
        }

        function interpretAndPauseAnimation(keyframePercentage) {
            start = undefined;
            previousTimeStamp = undefined;
            done = false;
            window.requestAnimationFrame(step);
        }

        window.requestAnimationFrame(step);

    </script>
</body>

</html>

2

Answers


  1. Rely on negative delays to get a specific point

    @keyframes colorAnim {
      0% {
        color: black;
      }
      50% {
        color: red;
      }
      100% {
        color: green;
      }
    }
    
    .animated-element-with-offset {
      animation: colorAnim 100ms infinite paused; 
      /* you can easily set the below using JS */
      animation-delay: -50ms; /* -1 * (50% of the duration) */
    }
    <div class="animated-element-with-offset" id="some-element-you-want-to-animate">
      Text Color Animation frame #50: Color expected is red
    </div>
    Login or Signup to reply.
  2. The best at controlling CSS animations through JS is certainly the Web Animations API.

    You can access a CSSAnimation object representing the CSS animation you’ve set on your element and then control its currentTime (and many more if needed). You can access its duration through the getTiming() method of its KeyframeEffect .effect.

    const element = document.getElementById("some-element-you-want-to-animate");
    // Grab the CSSAnimation object
    const [anim] = element.getAnimations().filter((anim) => anim.animationName === "colorAnim");
    // Get its duration and possible delay
    const { duration, delay } = anim.effect.getTiming();
    
    const input = document.querySelector("input");
    input.oninput = (evt) => {
      // Since the animation repeats, a value of 1 would reset to black
      anim.currentTime = delay + (duration * input.valueAsNumber);
    };
    input.oninput();
    @keyframes colorAnim {
      0% {
        color: black;
      }
    
      50% {
        color: red;
      }
    
      100% {
        color: green;
      }
    }
    
    .animated-element-with-offset {
      animation: colorAnim 100ms;
      animation-play-state: paused;
    }
    <div class="animated-element-with-offset" id="some-element-you-want-to-animate">
      Text Color Animation frame #50: Color expected at start is red
    </div>
    
    <input type=range min=0 max=0.99 step=0.01 value=0.5>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search