Firefox CSS动画平滑处理(亚像素平滑)

15

我正在创建一个CSS关键帧动画,使元素看起来像是慢慢漂浮。它嵌套在父元素中,其中一个使用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); 
  }
}

虽然这并没有解决你的子像素平滑问题,但你可以使用transition属性来帮助平滑定位。transition: all 2s ease 0s; - Etheryte
2个回答

14
每个浏览器的渲染引擎显然是不同的。例如,Firefox在CSS动画上没有实现抗锯齿效果。这并不本质上使它更好或更差,这取决于你正在进行的动画。例如,在Chrome中,线性过渡可能会出现不希望的模糊效果。
看起来您想要实现的是反锯齿/子像素平滑的过渡效果。我们无法改变引擎的渲染方式,但我们可以操纵动画使其对最终用户呈现更加柔和。
一切都没有失去 我修改了您的答案,并在原始答案旁边呈现了一个更平滑的版本。在Firefox中查看时,这应该会显得更加柔和。

点击查看比较

用于此效果的技术:
  • 使用线性过渡而不是ease。
  • 在动画对象上添加box-shadow。(软化边缘有助于创建虚假的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);}
}

最后一句话

您仍然可以稍微调整效果以适应您的要求。虽然不完美,但我希望它能够软化实际动画的结束效果。


它确实变软了,但对我来说,盒子的形状似乎发生了变化。当盒子向下移动时,它的高度变小了。当它向侧面移动时,宽度似乎也发生了变化。 - The Pragmatick
3
这句话需要翻译为:@ThePragmatick 至少可以说是一个不成熟的假设。我已经使用这种技巧几年了。我无法确定最初是从哪里学到的,因为那是很久以前的事情了。然而,在没有其他人愿意提供帮助的情况下,是我花了两个小时来为该操作编写一个可行的演示。 - DreamTeK
1
太棒了!这就解决了问题。令人惊讶的是,我的实际实现中实际上有第三个外部容器进行旋转。我在这里为演示目的将其删除了。将其分别旋转x和y容器并不能解决问题,但是给单独的x和y容器添加旋转确实使其更加平滑。谢谢! - Ryan
更新:在FF 41,OSX上,旋转(0.002度)技巧不再起作用。即使是旋转的文本在过渡/动画停止后也会出现反锯齿。 - Mikko Ohtamaa
1
在动态缩放精灵动画中,添加 rotate(0.05deg) 可以避免跳跃,这真是救了我的一命。 - swolfish
显示剩余2条评论

2

Use a small amount of rotation with the transformation. This forces Firefox to avoid the optimization and resample the image on every frame.

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


运行得非常好。 - chell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接