freedom
freedom

Reputation: 100

requestAnimationFrame appears to be invalid

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>

Upvotes: 0

Views: 146

Answers (2)

Kaiido
Kaiido

Reputation: 136755

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>

Upvotes: 0

wawan
wawan

Reputation: 497

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>

Upvotes: 2

Related Questions