1

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 2

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 causes 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>

Sign up to request clarification or add additional context in comments.

1 Comment

Awesome, thx. Unfortunately in my app the timing function is not linear...
-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/

4 Comments

Thx for the answer, but it does not work: jsfiddle.net/Imabot/53hLe2zq/5
@Fifi look at the new code
@Fifi check the code it works.
Thx, but this is no longer the answer to my initial question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.