CSS keyframe animation with translation transform

2019-06-15 08:10发布

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
   }
}

3条回答
【Aperson】
2楼-- · 2019-06-15 08:28

@Nemanja is correct you will find that if you tweak the speed you will see better results this is fairly typical with css animations. Also it doesn't really make a difference in this case if you enable hardware acceleration. I tidied up the code a little bit and ran it without any issues, i do not have ie10; However, I have 11. You may have to just remove the second transform of translateZ if it doesn't run in 10

body {
    background-color: #ccc;
}

.bobbing {
    position: absolute;  
    animation: bobbingAnim ease-in-out .5s infinite;
    -moz-animation: bobbingAnim ease-in-out .5s infinite;
    -webkit-animation: bobbingAnim ease-in-out .5s infinite;    
}

.bobbing.text {
    font-size: 50px;
    color: #000;
    left: 30px;
    top: 30px;
}

.bobbing.image {
    left: 30px;
    top: 150px;
    background: url(http://placehold.it/300x100/aa0000&text=Bobbing+image) 50% 50% no-repeat;
    width: 310px;
    height: 110px;
}

@keyframes bobbingAnim {
   50% {
       transform: translate(0, 12px) translateZ(0);       
   }
}

@-webkit-keyframes bobbingAnim {
   50% {
       -webkit-transform: translate3d(0, 12px, 0);       
   }
}

@-moz-keyframes bobbingAnim {
   50% {
       -moz-transform: translate3d(0, 12px, 0);       
   }
}
查看更多
ら.Afraid
3楼-- · 2019-06-15 08:37

There cant be half a pixel movement, there is no such thing.

Your problem is the speed and smoothness of the animation, not the "pixel snapping".

查看更多
手持菜刀,她持情操
4楼-- · 2019-06-15 08:40

I love your question! Good job in noticining 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 containt 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, so that 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
  }
}
查看更多
登录 后发表回答