CSS keyframe animation with translation transform snaps to whole pixels in IE 10 and Firefox

21,346

I love your question! Good job in noticing the pixel-snap in firefox and IE10.

I've researched this subject a while ago and I advise you to check the GSAP forums, as they contain a lot of useful information on web animations.

Here's a topic regarding IE10 pixel-snap issue.

What you need to do is add a minimal rotation to the element. This is so IE and Firefox will redraw it in a different way - which will stop pixel-snap for good :)

Tyr this:

@keyframes bobbingAnim {
  0% {
   transform: translate(0px, 0px) rotateZ(0.001deg);  
   animation-timing-function:ease-in-out
  }

  50% {
    transform: translate(0px, 12px) rotateZ(0.001deg);
    animation-timing-function:ease-in-out
  }

  100% {
   transform: translate(0px, 0px) rotateZ(0.001deg);
   animation-timing-function:ease-in-out
  }
}
Share:
21,346
Strille
Author by

Strille

Updated on July 18, 2022

Comments

  • Strille
    Strille almost 2 years

    It appears both IE 10 and Firefox snaps elements to whole pixels when animating their position using translate 2d transform in a css keyframe animation.

    Chrome and Safari does not, which looks a lot better when animating subtle movements.

    The animation is done the following way:

    @keyframes bobbingAnim {
       0% {
           transform: translate(0px, 0px);
           animation-timing-function:ease-in-out
       }
    
       50% {
           transform: translate(0px, 12px);
           animation-timing-function:ease-in-out
       }
    
       100% {
           transform: translate(0px, 0px);
           animation-timing-function:ease-in-out
       }
    }
    

    Here's an example of what I mean:

    http://jsfiddle.net/yZgTM/.

    Just open it in Chrome and IE 10 (or Firefox) and you should notice the difference in smoothness of the motion.

    I realise there might be many factors affecting this behaviour such as if the element is drawn with hardware acceleration or not.

    Does anyone know of a fix to try to force browsers to always draw the elements on subpixels?

    I found this similar question, but the answer was to animate using a translate transform, which is exactly what I'm doing: CSS3 Transitions 'snap to pixel'.

    Update: After playing around a bit I found a fix for Firefox, doesn't do anything in IE 10 though. The trick is to scale down the element ever so slightly and use translate3d with a 1px offset in the Z-axis:

    @keyframes bobbingAnim {
       0% {
           transform: scale(0.999, 0.999) translate3d(0px, 0px, 1px);
           animation-timing-function:ease-in-out
       }
    
       50% {
           transform: scale(0.999, 0.999) translate3d(0px, 12px, 1px);
           animation-timing-function:ease-in-out
       }
    
       100% {
           transform: scale(0.999, 0.999) translate3d(0px, 0px, 1px);
           animation-timing-function:ease-in-out
       }
    }