During heavy javascript function css animation stops if I use translateX(100%)

Viewed 404

Steps

  1. Go on REPL: https://codesandbox.io/s/css-sidebar-animation-100-transform-wxchf?file=/App.svelte
  2. click on "Toggle Sidebar" button
  3. the animation is smooth, smoothly
  4. uncomment line 28
  5. comment line 29
  6. click again on button
  7. the animation stops when heavy() function is called (in toggleSidebar() function)

Questions

I don't understand why this happens?

If I change -200px to -100% what is going on that causes the animation to stop?

How can I fix the problem? What if I don’t know the sidebar width in advance? What if it is dynamic?

Code

.sidebar {
  animation: sidebar-slide-right 3s ease-out;
}

@keyframes sidebar-slide-right {
  0% {
    /* transform: translateX(-100%); */
    transform: translateX(-200px);
  }
  100% {
    transform: translateX(0);
  }
}
1 Answers

I've spend some time testing your repl with performance time in web browser dev tools. My conclusions are:

In modern web browser we have

  • The Main thread
  • The Compositor thread

The second one is really nice because helps the main thread by taking some responsibilities on itself.

Typically, the main thread is responsible for:

  • Running your JavaScript.

  • Calculating your HTML elements’ CSS styles.

  • Laying out your page. Painting your elements into one or more bitmaps.

  • Handing these bitmaps over to the compositor thread.

Typically, the compositor thread is responsible for:

  • Drawing bitmaps to the screen via the GPU.

  • Asking the main thread to update bitmaps for visible or soon-to-be-visible parts of the page.

  • Figuring out which parts of the page are visible. Figuring out which parts are soon-to-be-visible when you’re scrolling.

  • Moving parts of the page when you scroll.

Source: http://sking7.github.io/articles/572118798.html

CSS-based animations, and Web Animations where supported natively, are typically handled on a thread known as the "compositor thread". This is different from the browser's "main thread", where styling, layout, painting, and JavaScript are executed. This means that if the browser is running some expensive tasks on the main thread, these animations can keep going without being interrupted.

Other changes to transforms and opacity can, in many cases, also be handled by the compositor thread.

If any animation triggers paint, layout, or both, the "main thread" will be required to do work. This is true for both CSS- and JavaScript-based animations, and the overhead of layout or paint will likely dwarf any work associated with CSS or JavaScript execution, rendering the question moot.

Source: https://developers.google.com/web/fundamentals/design-and-ux/animations/animations-and-performance

So compositor is pretty nice when we have to deal with animations. Using px as measure unit is easy and can be done by the compositor thread but using % makes our browser to calculate every "step" of our animation so the main thread has to help us with it. By using await you block the main thread so your browser waits to get recalculated position. When you use absolute unit the compositor thread executes the animation so even if you block the main thread, your animation is running smoothly.

Replace your code with

  async function toggleSidebar() {
    sidebarVisible = !sidebarVisible;
    console.log("1");
    await sleep(800);
    console.log("2");
    heavy(40);
  }

You can notice using % causes:

Animation runs

  1. console.log 1
  2. animation stops
  3. console.log 2
  4. animation runs

Using px:

  1. console.log 1
  2. Animation still runs
  3. console.log 2
  4. animation ends
Related