skip to Main Content

I am trying to pinpoint the cause and if possible find a fix or workaround for a performance issue I am having when updating the transform of about 200 span elements in Firefox.
In Chrome I am able to achieve smooth 60fps, but the same example in Firefox has huge performance issues which seem to be introduced when updating the rotate transform of the elements.

I have reproduced the issue here:
https://codepen.io/Epz-the-bold/pen/BaGvGLx

I have tested that removing the rotate transform part, Firefox keeps up with Chrome’s FPS at ~55-60fps.

Does anybody have any pointers on what is causing this issue and/or possible solutions?

To clarify why I am not using CSS transitions (which would work fine in FF) and instead updating the transforms on each frame: in my original code I am running a physics simulation to update the position and rotation of each span, so those should be managed by the physics engine to keep consistency between the DOM and the simulation.

2

Answers


  1. Chosen as BEST ANSWER

    Solution

    Adding transform-style: preserve-3d; to the spans completely fixed the issue, I am now seeing consistent fps in both Firefox and Chrome. My guess is this forces FF to use hardware acceleration in a case where translate3d and rotateZ were not working.

    Mitigation

    It seems that adding a short transition to the transform property helps mitigate this issue in Firefox, from my tests the transition duration should be higher than the average frame time or it'll cause more stuttering:

    transition: transform 100ms linear;
    

  2. Use transform: rotateZ() Instead of rotate(): Instead of using the rotate() function, try using rotateZ() with the transform property. rotateZ() is a 2D transformation and may have better performance in some cases.

    function update() {
      spans.forEach(span => {
        span.x += span.velocity.x;
        span.y += span.velocity.y;
        span.rotation += span.velocity.x * 0.01;
    
        // Update only the translate transform and use rotateZ()
        span.el.style.transform = `translate3d(${span.x}px, ${span.y}px, 0) rotateZ(${span.rotation}rad)`;
    
        const bb = span.el.getBoundingClientRect();
        // ... Rest of the code ...
      });
    
      requestAnimationFrame(update);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search