CSS盒子阴影-动画像素艺术闪烁

6
为了一部分好玩,一部分是我有的设计想法,我正在尝试将一个动态gif转换成纯CSS动画。
它几乎快要成功了,但我遇到了一个问题,不确定是什么原因导致的,或者我该如何解决。我不幸地怀疑我只是碰到了技术的限制。
我用来测试的gif是这个:https://us.v-cdn.net/5018289/uploads/editor/yj/lcdjneh1yoxv.gif 至于实际的CSS,我一直在尝试实现这里的方法(动画box-shadow属性),因为它似乎是最可行的:https://codepen.io/andrewarchi/pen/OXEEgL
#ash::after {
  animation: ash-frames 0.4s steps(1) infinite;
}

@keyframes ash-frames {
    0% {box-shadow: 32px 8px #181818, 40px 8px #181818,...}
    ...
}

在给定的示例中,动画似乎相当流畅,所以我觉得值得一试。明显的区别是:我使用的gif有更多的帧和更多的像素。
快速概述一下我的CSS(我正在使用供应商标记等,这只是一个示例):
.pixel-art-3940::after {
    animation: pixel-art-3940-frames 1s steps(5, end) infinite;
}

@keyframes pixel-art-3940-frames {
    0% {box-shadow: 112px 68px rgba(77, 69, 64, 1),...}
    16.666666666666668% {box-shadow:115px 65px rgba(77, 69, 64, 1),...}
    ...
}

动画似乎确实在工作,但是动画上有一种强烈的“闪烁”效果。请参见下文:

flickering animation

我已经尝试了在Chrome中解决“闪烁转换”的常规方法,比如将-webkit-backface-visibility设置为hidden,但到目前为止没有任何解决办法。就像我所说的,我担心这只是技术本身的限制。有什么想法可能是问题所在,以及我是否可以解决它?编辑:这个特定动画的完整源代码可以在这两个Gist中找到。我选择使用Gist是因为CSS文件的大小。

这个 CodePen 展示了一个看起来很好的 Pokemon 动画,你有你所询问的东西的代码放在哪里可以重现所展示的内容吗? - Chris W.
@ChrisW。我已将完整源代码添加到问题中。 - CGriffin
1个回答

3

正确答案

最终,问题出在animation-timing-function上。在steps()函数中的第一个参数不是关键帧的数量(或循环中步数的数量),而是在关键帧之间呈现的步骤数。

因此将其更改为steps(1, end)可以解决问题,因为浏览器不再需要计算中间帧(由于box-shadow值过多而失败-每个像素基本上都有1个值 - 顺便说一句,这是一种非常棒的技术)

查看它的工作方式:https://jsfiddle.net/websiter/wnrxmapu/2/


以前的答案:部分错误,导致正确答案 - 我保留它可能对其他调试类似动画的人有帮助):

一开始我认为你的导出工具... 简直是错的。

为什么? 因为将animation-duration1s增加到100s会产生这个结果

显然结论是你的中间帧有问题。

但是,我对每个中间帧进行了单独测试,并且出乎意料地它们都正确呈现了。

这导致结论是每个关键帧中box-shadow的计算次数受到限制,并执行某种聚类算法。

这很有道理,因为我们在谈论box-shadow,在99.999999999%的情况下(基本上是全部),不需要精确。 它应该被近似,以获得更快速的渲染速度,原因显而易见:我们正在关心用户体验和“感觉”。 大多数用户都不具备技术能力,他们只是期望在任何情况下都能流畅滚动。

在尝试优化您的代码后,我得出结论必须对每个关键帧允许的计算量进行限制,将其缩小至初始大小的不到一半:https://jsfiddle.net/websiter/wnrxmapu/1/

我无法找到任何像素聚类box-shadow技术的材料,我认为在线上没有太多可用的 - 这应该是机密信息。

然而,就我个人而言,除了炫耀之外,与gif或svg相比,我不认为你的技术在渲染性能方面有机会。重点强调"IMHO"。如果您坚持要完成此操作,可能需要将图像分割并检查允许计算的限制是每个元素还是每个页面。

但我不会抱太大的希望。正是像你的代码所揭示的优化使得CSS变得极快。如果它必须准确无误,它就不会那么快。


我在你编辑之前就看到了这个答案,不得不说,我简直无法相信我没有想到减缓动画速度来检查出现了什么问题。在减慢速度并放大尺寸后,我终于确定了“闪烁”实际上是box-shadow从一个“帧”(CSS动画步骤)过渡到另一个的结果!解决方案实际上非常简单。我没有为动画定义一组步骤,而是将规则设置为step-end,然后一切都消失了。 - CGriffin
说实话,我不确定如何从SO的角度来处理这个问题。你的答案,在编辑之前,让我找到了解决方案 - 但是,在编辑之后,无论它有多么信息丰富和写得好,都没有包含解决方案。但是,你是唯一回答的人!所以我想我会继续说,如果你能从你的编辑中提取一些上下文信息并将其添加到原始答案中,那就赢了。 - CGriffin
我很惊讶我没有注意到你的 steps(5, end)。由于某种原因,我一直认为你的动画是正确的。当然应该是 steps(1,end)。关于改进答案:这个答案仍然包含原始答案。我确实说过:我最初认为你的步骤是错误的。我也说过当时和现在我是如何得出结论的(将其放大)。如果你将计时函数更改为 linear 并将其放大,你会发现我的答案是正确的。计算是有限制的。 - tao
最后,我很高兴能帮助你让它正常工作,并希望你会发现转换为十六进制的功能很有用。这确实将字符长度从1.9M降低到不到900k。祝编码愉快。 - tao
我记得以前也遇到过这个问题。steps() 函数的第一个参数不是总关键帧数,而是在关键帧之间渲染的步骤数 - tao
显示剩余2条评论

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