skip to Main Content

I have an animated HTML element (box) as follow:

<div id="box"></div>

The box is initially animated to 200 pixels to the right with a duration of 4 seconds.

.anim {
    animation-name: anim;
    animation-duration: 4s; 
    animation-timing-function: linear; /* cubic-bezier(0.1, -0.6, 0.2, 0); */
}

@keyframes anim {
    0% { left: var(--xs); }
    100% { left: var(--xe); }
}

Here the JavaScript that starts the animation:

var box = document.getElementById('box');

box.style.setProperty('--xs', '0px');
box.style.setProperty('--xe', '200px');
box.classList.add('anim');

After one second, the final position is updated to 400 pixels:

setTimeout(() => {
    box.style.setProperty('--xe', '400px');
},1000)

Of course, when the final position is updated, the box jumps from one position to the other. Is there a way to get a smooth transition to avoid the "teletransportation" effect?

Here is the JSFiddle: https://jsfiddle.net/Imabot/53hLe2zq/

2

Answers


  1. you can use the following code to create a smooth transition between the two states:

    CSS:

    #box {
      width: 50px;
      height: 50px;
      background-color: red;
      position: relative;
      left: 0px;
      border-radius: 15px;
      transition: left 4s ease-out;
    }
    
    #box.animate {
       left: 400px;
    }
    
    @keyframes anim {
        0% { left: var(--xs); }
        100% { left: var(--xe); }
    }
    

    HTML:

    <div id="box"></div>
    

    JS:

    var box = document.getElementById('box');
    setTimeout(function() { box.classList.add('animate'); }, 1000);
    

    This will create a smooth transition between the two states, with a duration of 4s.

    Here is the JSFiddle: https://jsfiddle.net/1fuq9ebL/

    Login or Signup to reply.
  2. Change its animation-duration to 8 seconds:

    setTimeout(() => {
        box.style.setProperty('--xe', '400px');
        box.style.animationDuration = '8s';
    }, 1000);
    

    Originally, the box was meant to move 200 pixels in 4 seconds; by a simple division we know that its speed is set to 50px/s.

    ┌──────┐
    │ 50/s │                            (4s away)
    └──────┘
    |-------------------|-------------------|
    0                  100                 200
    

    After one second, when the callback is fired, the length suddenly doubles to 400; this cause the box’s speed to increase to 100px/s. However, since it is already 50px from the original position, it must "teleport" to 100px to be able to travel the rest in 3 seconds.

              ┌──────┐
              │ 50/s │                                                          (3s away)
              └──────┘
    |---------|---------|-------------------|-------------------|-------------------|
    0         50       100                 200                 300                 400
    
                        ┌──────┐
                        │ 100/s│                                                (3s away)
                        └──────┘
    |---------|---------|-------------------|-------------------|-------------------|
    0         50       100                 200                 300                 400
    

    So, to prevent it from teleporting we need to give it more time, making its speed remain consistent. Again, we need math:

    ( 400  -  50 ) /  50   = 7    (seconds)
    To_be_traveled / Speed = Time
    

    Add it to 1 second we already used to travel the first 50 pixels and we have the final answer: 8 seconds.

    And that’s all there is to it! Should your actual input changes, you can simply convert the formula above to a function. Note that this won’t work with any animation-timing-function other than linear.

    Try it:

    var box = document.getElementById('box');
    
    box.style.setProperty('--xs', '0px');
    box.style.setProperty('--xe', '200px');
    box.classList.add('anim');
    
    setTimeout(() => {
        box.style.setProperty('--xe', '400px');
        box.style.animationDuration = '8s';
    }, 1000)
    #box {
        width: 40px;
        height: 40px;
        background-color: red;
        border-radius: 15px;
        position: relative; 
    }
    
    .anim {
        animation-name: anim;
        animation-duration: 4s; 
        animation-timing-function: linear;
    }
    
    @keyframes anim {
        0% { left: var(--xs); }
        100% { left: var(--xe); }
    }
    <div id="box"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search