0

I watched Jake Archibald's talk recently. He gave an example in his speech where he says to use requestAnimationFrame twice to delay applying a CSS style to perform a CSS animation.

See https://youtu.be/cCOL7MC4Pl0?t=1337

I reproduced the example to test it, but without luck:

The box will move directly to a position of 500px, instead of going from 1000px to 500px.

Jake Archibald's a solution was proposed. use a two-layer nested requestAnimationFrame

image

But it doesn't seem to work for me. Why?

Here is the code snippet that should work but doesn't:

const box = document.getElementById("box");
box.addEventListener("click", ()=>{
  box.style.transform = 'translateX(500px)';
  box.style.transition = 'transform 1s ease-out';
  requestAnimationFrame(()=>{
    requestAnimationFrame(()=>{
        box.style.transform = 'translateX(250px)';
    });
  });
});
#box {
  background-color: salmon;
  height: 100px;
  width: 100px;
  cursor: pointer;
}
<div id="box">box</div>
jlh
  • 4,349
  • 40
  • 45
freedom
  • 110
  • 2
  • 11
  • can you specify the link of the speech? – a.barbieri Mar 06 '20 at 07:28
  • https://www.youtube.com/watch?v=cCOL7MC4Pl0 – freedom Mar 06 '20 at 07:31
  • I actually see you problem. Can you approve the edit I've done to your question? That might allow other people to better understand the question and answer. – a.barbieri Mar 06 '20 at 08:14
  • Hey @Kaiido, I guess is a matter of browser version. Your example moves to the right after the click, whereas it's expected to go left. (Chrome 80.0.3987.132 and Firefox 73.0.1) Where are you testing it? – a.barbieri Mar 06 '20 at 08:28
  • Your code snippet appears to work on both Firefox and Chrome for me. – MiK Mar 06 '20 at 08:41
  • Following his explanation, I think the code might actually have an error. `box.style.transition = 'transform 1s ease-out';` should be inside the `rAF` callback, otherwise the element is already in an animated state (on it's way from 0 to 1000px), and the browser might (this is my guess) simply *collapse* those instructions. As in, *"oh, you're already animating, and are at position X, but now the final position has changed, well then just go to there..."*. – Yoshi Mar 06 '20 at 09:13

2 Answers2

2

Something like this ?

const box = document.getElementById("box");
box.addEventListener("click", ()=>{
  box.style.transform = 'translateX(500px)';
  requestAnimationFrame(()=>{
    box.style.transition = 'transform 1s ease-out';
    requestAnimationFrame(()=>{
        box.style.transform = 'translateX(250px)';
    });
  });
});
#box {
  background-color: salmon;
  height: 100px;
  width: 100px;
  cursor: pointer;
}
<div id="box">box</div>
wawan
  • 497
  • 6
  • 11
0

I really hate videos so I didn't checked it entirely, but certainly they already had that #box element translated before they call that javascript.

If they didn't then it would actually perform the transition from translateX(0) to translateX(1000px) during one frame, and right after transition from wherever it was (probably not far from begining left) to translateX(250px).

So for a fix, you can set the initial translateX value in CSS.

const box = document.getElementById("box");
box.addEventListener("click", ()=>{
  box.style.transform = 'translateX(500px)';
  box.style.transition = 'transform 1s ease-out';
  requestAnimationFrame(()=>{
    requestAnimationFrame(()=>{
        box.style.transform = 'translateX(250px)';
    });
  });
});
#box {
  background-color: salmon;
  height: 100px;
  width: 100px;
  cursor: pointer;
  transform: translateX(1000px);
}
You have to scroll to the right now.
<div id="box">box</div>

Now, you should really not use that double requestAnimationFrame hack. Instead identify the problem and use a proper fix (i.e force a reflow).

const box = document.getElementById("box");
box.addEventListener("click", ()=>{
  box.style.transform = 'translateX(500px)';

  box.offsetWidth; // force reflow so our box is translated to initial position
  box.style.transition = 'transform 1s ease-out';
  box.style.transform = 'translateX(250px)';
});
#box {
  background-color: salmon;
  height: 100px;
  width: 100px;
  cursor: pointer;
}
<div id="box">box</div>
Kaiido
  • 123,334
  • 13
  • 219
  • 285