【问题标题】:Webkit animation is leaving junk pixels behind on the screenWebkit 动画在屏幕上留下垃圾像素
【发布时间】:2012-04-16 12:46:00
【问题描述】:

以下代码在屏幕上放置一个白框。如果您在 iPad 上运行它(您也可以调整像素以在 iPhone 上运行它),当您触摸该框时,它会从屏幕上滑出,并在其底部边缘留下白色像素的痕迹。

<!DOCTYPE HTML>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-height, user-scalable=no, maximum-scale=1, minimum-scale=1" />
    <title>Line Bug Demo</title>
    <style>
body {
  background: black;
}
.panel {
  background: white;
  position: absolute;
  z-index: 2;
  width: 1000px;
  height: 500px;
  top: 34px;
  left: 12px;
  -webkit-border-radius: 20px;
  -webkit-transition: left 0.333s ease-in-out;
}
.panel.hide {
  left: -1000px;
}
    </style>
  </head>
  <body>
    <div class="panel" onclick="this.setAttribute('class', 'panel hide')"></div>
  </body>
</html>

解决这个问题的关键是使用边界半径,并做动画。如果您只是将其从屏幕上弹出,则没有踪迹。如果没有边界半径,就没有轨迹。

以下是我目前发现的解决方法:

.panel.hide { -webkit-border-radius: 0; }

丑陋,而且对我的应用程序来说不太实用,因为我正在为面板内外设置动画,而且我真的想要在屏幕上显示圆角。

另一个:

.panel { -webkit-transform: translateZ(0); }

这会将面板放入硬件管道中,从而正确地进行合成。虽然这适用于这个简单的演示,但在我的真实 Web 应用程序中使用硬件管道会导致内存不足错误。 (种类繁多,种类繁多。)

关于如何摆脱这条线索的任何其他想法?

【问题讨论】:

  • 你试过-webkit-backface-visibility: hidden;吗?
  • 当然这是一个错误。你如何做动画并不重要。
  • 这是一个老问题,但my answer here 解释了原因。简而言之,Quartz 抗锯齿绘制了一排微弱的半透明像素,这些像素位于元素的计算高度和宽度之外,因此它们永远不会在重新绘制时被清除并构建每个动画帧。如果您愿意,我可以建议一个依赖硬件加速的简单修复?
  • @jesmith 太好了!简单地说,我的想法是通过在每个方向上将盒子的计算尺寸增加一个像素来强制 WebKit 重新绘制额外的像素。不幸的是,我没有旧的 iOS 设备可供测试,所以您介意为我尝试一些建议吗?第一个建议:将box-shadow: 0 0 1px rgba(0,0,0,.05); 添加到.panel 规则集中。视觉影响应该是最小的,但它会强制在每个边缘上绘制额外的一行像素。 (如果这不起作用,请尝试稍微增加 alpha。)
  • @JordanGray,效果很好。我很感激。

标签: css ios animation webkit mobile-safari


【解决方案1】:

我会做什么:

  • -webkit-backface-visibility: hidden
  • 使用-webkit-transform:translateX(left value here) // 或translate-3d(x,y,z) 进行动画处理,应禁用左侧 [*]

请务必检查在 parent 上启用硬件加速是否有任何不同。

还有一些简单的方法可以强制重绘 - 如果您还需要有关它们的信息,请告诉我。

[*] 依赖 3d 变换是一种 hack,应该谨慎使用,它是 GPU 和内存之间的权衡,在某些情况下它可能会导致动画卡顿或内存问题(想想 - 移动设备,强制 GPU 加速大地区)。

CSS will-change 属性将是标记可以提前优化的属性的正确位置。

【讨论】:

  • -webkit-backface-visibility: hidden 就像一个魅力!非常感谢。
  • 多亏了这个,我为自己赢得了朋友的芒果奶茶。大声笑!
【解决方案2】:

解决方案

box-shadow: 0 0 1px rgba(0, 0, 0, 0.05);

如果您觉得这太明显,您可以使用框的背景颜色作为box-shadow 颜色。

或者,根据answer on a similar issue in Chrome(感谢 cmets 中的Sebastian 提供的提示),您可能想尝试:

outline: 1px solid transparent;

发生了什么事?

我在别处给了fairly lengthy explanation,但这里是简短版本。出于性能原因,WebKit 仅重绘页面中它认为可能已更改的那些部分。但是,iOS(7 之前)的 Safari 实现的边框半径抗锯齿超出了计算的框尺寸之外的几个像素。由于 WebKit 不知道这些像素,它们不会被重绘;相反,它们被留下并在每个动画帧上累积。

通常的解决方案——正如我在其他答案中所建议的——是强制该元素需要硬件加速,以便将其绘制为单独的层。但是,过多的小元素或少数大元素会导致大量图块被推送到 GPU,从而对性能产生明显影响。

使用box-shadow 更直接地解决了这个问题:它扩展了框的重绘尺寸,迫使WebKit 重绘额外的像素。 box-shadow 在移动浏览器中的已知性能影响与使用的模糊半径直接相关,因此一个像素的阴影应该几乎没有影响。

【讨论】:

  • 这行得通。我没有看到性能下降。请注意,在追查您答案中的链接时,我了解到 iOS 7 据称已修复了底层的石英错误。
  • @jesmith 我看到有人在对另一个问题的评论中也有同样的看法,但我找不到一个好的参考链接——如果你有一个,我将非常感激!顺便说一句,我更深入地研究了 WebKit 源代码并阅读了 Quartz 抗锯齿,看看我是否可以进一步缩小范围,但我还没有到可以给出自信和准确的阐述的地步。
  • 我已经在使用盒子阴影,但另一个技巧为我做了:感谢这篇文章:stackoverflow.com/a/12352196/807397 我正在使用outline: 1px solid transparent;,它就像一个魅力!
  • @Sebastian 这很简洁,而且更简洁——感谢您的提醒!我认为outline 可能有效,但一直没有时间测试它。也许我应该更新我的答案以链接到该解决方案。
  • 天哪。这真太了不起了。谢谢!
猜你喜欢
  • 2013-09-23
  • 2012-01-21
  • 1970-01-01
  • 2013-06-16
  • 1970-01-01
  • 1970-01-01
  • 2021-06-30
  • 2012-05-09
  • 2021-05-20
相关资源
最近更新 更多