Firefox CSS 动画平滑(子像素平滑)

Firefox CSS Animation Smoothing (sub-pixel smoothing)

我正在创建一个 CSS 关键帧动画,使元素看起来好像 casually/slowly 漂浮了一下。它嵌套在父级中,一个使用 translateX() 缓慢地左右移动,一个使用 translateY() 缓慢地独立地上下移动。

Chrome 和 Safari 完美地呈现了这一点,赋予它逐渐摇摆的运动。它使动画平滑(也许使用子像素平滑?),使一切看起来非常平滑。然而,Firefox 逐个像素地对其进行动画处理,因此您可以看到它在每个像素处跳跃,而不是平滑地左右摇摆。

查看Chrome和FireFox中的JSFiddle查看区别:http://jsfiddle.net/gonygdfz/6/

有什么方法可以让 FireFox 平滑地渲染这个而不是逐个像素地跳跃?这点在实际应用中表现得非常明显。

标记:

<div id="parent">
    <div id="move-x">
        <div id="move-y">
            <div id="child"></div>
        </div>
    </div>
</div>

CSS:

#parent {
    width: 400px;
    height: 326px;
    background-color: yellow;
    background: url(http://paint.net.amihotornot.com.au/Features/Effects/Plugins/Render/Grid_CheckerBoard_Maker/Grid_CheckerBoard_Maker.Paint.NET.001.png) top center repeat;
}

#child {
    position: absolute;
    top: 75px;
    left: 150px;
    width: 100px;
    height: 100px;
    background-color: black;
    animation: range-y 10s infinite ease;
}

#move-x { 
    animation: range-x 10s infinite ease; 
    -webkit-animation: range-x 10s infinite ease;
}
#move-y { 
    animation: range-y 15s infinite ease; 
    -webkit-animation: range-y 15s infinite ease;
}

@keyframes range-x {
  0%   { 
    transform: translateX(0); 
  }
  30% {
    transform: translateX(-8px); 
  }
  50% {
    transform: translateX(1px); 
  }
  65% {
    transform: translateX(6px); 
  }
  80% {
    transform: translateX(0px); 

  }
  89% {
    transform: translateX(-3px); 
  }
  100% {
    transform: translateX(0); 
  }
}


@keyframes range-y {
  0%   { 
    transform: translateY(0); 
  }
  20% {
    transform: translateY(13px); 
  }
  35% {
    transform: translateY(-1px); 
  }
  70% {
    transform: translateY(-14px); 
  }
  90% {
    transform: translateY(2px); 
  }
  100% {
    transform: translateY(0); 
  }
}


@-webkit-keyframes range-x {
  0%   { 
    transform: translateX(0); 
  }
  30% {
    transform: translateX(-8px); 
  }
  50% {
    transform: translateX(1px); 
  }
  65% {
    transform: translateX(6px); 
  }
  80% {
    transform: translateX(0px); 

  }
  89% {
    transform: translateX(-3px); 
  }
  100% {
    transform: translateX(0); 
  }
}


@-webkit-keyframes range-y {
  0%   { 
    transform: translateY(0); 
  }
  20% {
    transform: translateY(13px); 
  }
  35% {
    transform: translateY(-1px); 
  }
  70% {
    transform: translateY(-14px); 
  }
  90% {
    transform: translateY(2px); 
  }
  100% {
    transform: translateY(0); 
  }
}

每个浏览器的渲染引擎明显不同。 Firefox 不对 CSS 动画实现抗锯齿效果。这并不能从本质上使它变得更好或更坏,它仅取决于您要设置动画的内容。例如,在 Chrome 中,线性过渡可能会出现令人不快的模糊。

看来您想要实现的是 anti-aliased/sub-pixel 平滑过渡。我们无法更改引擎呈现的方式,但我们可以操纵动画让最终用户看起来更柔和。


万事俱备

我已经修改了您的答案并在您的原始版本旁边呈现了一个更流畅的版本。在 Firefox 中查看时应该会显得更柔和。

CLICK FOR COMPARISON

用于此效果的技术:

  • 线性过渡而不是缓和。
  • 动画对象上的框阴影。 (软化边缘有助于创建假 AA 效果)
  • 旋转对象。添加最小旋转有助于更好地利用渲染引擎。

CSS

#parent {
    width: 50%;
    float:left;
    height: 326px;
    background-color: yellow;
    background: url(http://paint.net.amihotornot.com.au/Features/Effects/Plugins/Render/Grid_CheckerBoard_Maker/Grid_CheckerBoard_Maker.Paint.NET.001.png) top center repeat;
}
#child {
    position: absolute;
    top: 75px;
    left: 150px;
    width: 100px;
    height: 100px;
    background-color: black;
    box-shadow:0 0 1px rgba(0,0,0,0.7);
    animation: range-y 10s infinite linear;
    -webkit-animation: range-y 10s infinite linear;
}
#move-x { 
    animation: range-x 10s infinite linear; 
    -webkit-animation: range-x 10s infinite linear;
}
#move-y { 
    animation: range-y 15s infinite linear; 
    -webkit-animation: range-y 15s infinite linear;
}
@keyframes range-x {
    0%   {transform: translateX(0);}
    30%  {transform: translateX(-8px) rotate(0.02deg);}
    50%  {transform: translateX(1px) rotate(0deg);}
    65%  {transform: translateX(6px) rotate(0.02deg);}
    80%  {transform: translateX(0px) rotate(0deg);}
    89%  {transform: translateX(-3px) rotate(0.02deg);}
    100% {transform: translateX(0) rotate(0deg);}
}
@keyframes range-y {
    0%   {transform: translateY(0);}
    20%  {transform: translateY(13px) rotate(0.02deg);}
    35%  {transform: translateY(-1px) rotate(0deg);}
    70%  {transform: translateY(-14px) rotate(0.02deg);}
    90%  {transform: translateY(2px) rotate(0deg);}
    100% {transform: translateY(0) rotate(0.02deg);}
}
@-webkit-keyframes range-x {
    0%   {transform: translateX(0);}
    30%  {transform: translateX(-8px) rotate(0.02deg);}
    50%  {transform: translateX(1px) rotate(0deg);}
    65%  {transform: translateX(6px) rotate(0.02deg);}
    80%  {transform: translateX(0px) rotate(0deg);}
    89%  {transform: translateX(-3px) rotate(0.02deg);}
    100% {transform: translateX(0) rotate(0deg);}
}
@-webkit-keyframes range-y {
    0%   {transform: translateY(0);}
    20%  {transform: translateY(13px) rotate(0.02deg);}
    35%  {transform: translateY(-1px) rotate(0deg);}
    70%  {transform: translateY(-14px) rotate(0.02deg);}
    90%  {transform: translateY(2px) rotate(0deg);}
    100% {transform: translateY(0) rotate(0.02deg);}
}

最后一句话

您仍然可以通过任何一种方式稍微调整效果以满足您的要求。 它并不完美,但我希望它有助于柔化实际动画的最终效果。

在变换中使用少量旋转。这迫使 Firefox 避免优化并在每一帧上重新采样图像。

@keyframes optimized {
  0%{
    transform: translateX(0%);
  }
  100%{
    transform: translateX(200px);
  }
}

@keyframes subpixel {
  0%{
    transform: translateX(0%) rotate(0.1deg);
  }
  100%{
    transform: translateX(200px) rotate(0.1deg);
  }
}

div{
  width:5px;
  height:50px;
  background-color: red;
  animation-duration:30s;
  animation-iteration-count: infinite;
  animation-direction:alternate;
  animation-timing-function:linear;
}

.optimized{
  animation-name: optimized;
  margin-bottom:1px;
}

.subpixel{
  animation-name: subpixel;
}
<div class="optimized">
</div>
<div class="subpixel">
</div>