在可滚动的绝对定位div中,相对定位的元素"滞后"于滚动

16
我有一个使用PhoneGap制作的应用程序,其中包含带有标题、表格和图像的相当长的文本,我正在Android上进行测试。除了具有样式position:relative的元素之外,一切都正常。当滚动页面时,这些元素会“滞后”,也就是说,如果我滚动页面,那么这些元素会在大约四分之一秒后开始和结束滚动。
当组合绝对div与相对子元素以及带有overflow:auto的子元素时,会出现此错误。删除其中任何一个都可以修复该错误,但如果可能的话,我更愿意保留它。尽管如果必须的话,我愿意删除表格并将其单独显示(例如在对话框中)。
此错误仅出现在标准的Android浏览器(当然还有我的PhoneGap应用程序)中。到目前为止,我已经使用以下设备进行了测试:
  • Samsung Galaxy Nexus (4.1.1)
  • Samsung Galaxy S III (4.1.2)
任何帮助都将不胜感激,但我更喜欢不改变HTML和功能的解决方案(或者尽量不改变)。

after quick scrolling

我创建了一个最小示例来展示这个bug。只需在您的安卓设备上打开它并开始滚动,您应该立即看到问题:
<!doctype html>
<html>
<head><meta name="viewport" content="initial-scale=1.0"></head>
<body style="margin:0">

<div style="position:absolute;overflow:auto;top:100px;bottom:100px;width:100%">

  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam a quam arcu. Duis ultrices mollis nibh ut hendrerit. Etiam a interdum metus. Integer volutpat, nibh laoreet euismod suscipit, libero sem iaculis lorem, ut hendrerit magna orci eu elit. Nulla eu ultricies libero. Nulla facilisi. Maecenas nec turpis vitae magna lobortis ornare sit amet ut lacus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc vestibulum lobortis orci, sit amet ornare dui congue nec. Morbi id magna at turpis auctor ultricies. Ut rhoncus quam augue, ut consectetur risus.</p>
  <div style="position:relative;background:red;">relative box<br>moves slower than the other text</div>
  <p>Fusce congue orci a nunc gravida sed pretium lorem convallis. Etiam hendrerit, ligula eget lobortis vestibulum, arcu sapien pharetra magna, auctor suscipit nisl tellus quis lacus. Cras id elit at ante mollis venenatis. Donec eu sollicitudin odio. Aliquam erat volutpat. Cras et tortor sed mi faucibus sagittis non quis metus. Morbi mauris ante, posuere vel rutrum id, mattis id enim. Morbi purus quam, euismod facilisis blandit quis, commodo at justo. Aliquam in fermentum nibh. Curabitur pharetra blandit risus sit amet tristique. Suspendisse potenti. Curabitur interdum eleifend justo, et dapibus justo volutpat sed.</p>          
  <div style="overflow:auto">
    <table>
      <tr><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th></tr>
      <tr><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td></tr>
    </table>
  </div>

</div>
</body>
</html>

请提供一个jsfiddle、tinkerbin或liveweave。 - George Katsanos
我已更新帖子并附上链接。这些服务不幸地不能让你添加元标头。 - Thomas
有没有通过强制硬件加速来解决这个问题的机会?我停止使用PhoneGap是因为出现了滚动问题,但我通过添加一个值为0的translate3d通常可以在视觉上解决这些问题。这对你有帮助吗? - Leeish
+Leeish 感谢你的建议。这就是我要采用的解决方案。 - Thomas
4个回答

33
简而言之,你所遭受的问题是常见且有记录的。在桌面和移动浏览器中,具有overflow:autooverflow:scroll属性的元素存在绘制/回流/渲染问题。此外,在移动浏览器(iOS和Android上的webkit)中存在相对和绝对元素未呈现的问题,如果它们“离屏”,这可能会导致滚动时出现延迟。
有一些“hack” shim可以应用:
element {
    -webkit-overflow-scrolling: touch;
}

element > * {
    -webkit-transform: translateZ(0px);
}

element > * {
    -webkit-transform: translate3d(0,0,0);
}

一些阅读材料:

以下是我从某个地方复制到笔记中的一小段代码,现在无法找到来源:

特别是那些严重依赖滚动条的网站上,你可能会发现你的主要内容依赖于overflow:scroll。这是一个真正的挑战,因为这种滚动方式没有进行任何GPU加速,所以每当用户滚动时,内容都会重新绘制。你可以使用普通页面滚动(overflow:visible)和position:fixed来解决这些问题。


谢谢!顺便说一下,这个引用来自http://addyosmani.com/blog/devtools-visually-re-engineering-css-for-faster-paint-times/。 - Thomas
最后两个CSS片段有效。我感觉很愚蠢,因为我之前读过这些内容,但是不知怎么回事,没意识到它们必须应用于滚动元素的子元素:D 在性能和支持方面,使用哪一个更重要吗?即使没有问题,是否建议使用它?我担心它会减慢渲染速度,特别是当有很多元素时。 - Thomas
这个错误已经被记录在哪里了吗? - agaase
@mivaas19 没有,我没有。它应该放在哪里呢?它只会发生在默认的Android浏览器中,而不会发生在任何其他WebKit浏览器中。 - Thomas
我也在开发PhoneGap Android应用,但是元素仍然很卡顿。我知道问题出在我更新图片上,请问你有什么建议吗? - santhosh
显示剩余4条评论

2
我认为你有两个问题要解决。一个是下方滑动的文本,另一个是滚动速度慢的问题?
我不确定你想用版权符号做什么,但我不会将行高设为小于1或1em。试着使用父元素并从中样式化span。你可以在span上使用"display:inline-block; vertical-align: middle;"来获得所需的效果。
<p><span>&copy;</span>Some text</p>

滚动条的行为取决于你在做什么。移动浏览器会等待300毫秒以查看您是滚动还是单击链接<a>标签。可能与此相关,如果是这样,建议使用Google FastClick
移动浏览器会加速页面在body上的滚动。因此,使用嵌套的div或position:absolute可能会使您无法获得更快的滚动速度。在更新版本的Android和iOS中,您可以使用-webkit-overflow-scrolling: touch来帮助解决问题,但对于旧手机无效。我建议尽量避免使用绝对定位,因为根据您的示例,似乎并不需要它,而且使用可滚动的嵌套div需要一些用户在div内使用两个手指来滚动内容。我建议尽量避免这种情况,并将设计替换为更适合移动端的设计模式,例如展开内容的链接。
许多滚动问题在尝试支持移动设备上的position:fixed时浮出水面,如果您认为这可能是原因,并且想阅读更多信息,请参考:http://bradfrostweb.com/blog/mobile/fixed-position/

我只是遇到了一些问题,特定元素(position:relative)滚动时会有不同的滚动延迟,所以当你滚动时它看起来有点像视差滚动。很难解释,所以我添加了一个截图。 对于版权符号,我从我们的网站复制了一些CSS,在表格单元格中使用vertical-align:top时,某些浏览器无法正确呈现上标和下标。 - Thomas
最外层的div是我的应用程序的内容区域。它被绝对定位以留出页眉和页脚的空间。或者有更好的方法吗? 当我删除表格时,错误实际上消失了,因此水平溢出似乎是问题所在。 - Thomas
不要使用绝对定位。如果只是为了移动端,请将标题、内容区域和页脚堆叠在一起,并设置100%的宽度。 - Jesse

1

移除 position:absoluteposition:relative,它们对于此布局绝对不需要,并且会导致所有问题。

如果您希望,可以为您的 body 添加一些 margin-top

PhoneGap 会生成一些类似垃圾的 html,希望您能对 CSS 进行精细控制。


发布的代码只是一个最小的示例。我需要绝对定位,因为我需要动画效果,而且我还需要在对话框中显示内容。我需要相对定位来将子元素绝对定位。简而言之,我需要它来复制我们网站的一些设计元素。 至于你所说的PhoneGap HTML垃圾,那都是我的垃圾 :D - Thomas
相对定位和绝对定位在移动浏览器中会出现问题,并且支持程度可能会有很大差异。你知道如何进行远程Web开发检查吗?这就是你可以玩转CSS并查看其是否有效的方法。以下是操作步骤:https://developers.google.com/chrome-developer-tools/docs/remote-debugging 一旦设置完成,你就是王者了。你知道如何使用Dev工具吗? - George Katsanos
很遗憾,我无法删除它们。特别是如果外部div是必须是绝对定位的对话框。 是的,我知道如何使用DevTools,但我从未远程操作过。你提供的链接中的方法不幸只适用于Chrome(在那里它运行良好)。但我已经在PhoneGap Build的调试功能中测试了它。它正在使用weinre,我会看一下它。 - Thomas
你发送的链接只能在Chrome浏览器中使用,因为它是Chrome开发者工具的一个功能。不幸的是,我已经尝试了几个小时,但没有成功... - Thomas
实际上,绝对定位的盒子是相对于相对定位的盒子放置的,因此尝试在这两个div中反转position:absolute和position:relative的位置,看看会发生什么。众所周知,相对定位的盒子可能不知道如何/在哪里放置(或者占用了body..)。 - George Katsanos

0
其实这个问题有一个简单的CSS解决方案,只需要在你的段落中添加position:relative即可解决问题。
试试这个:
<!doctype html>
<html>
<head><meta name="viewport" content="initial-scale=1.0">
<style>
p{ position:relative;}
</style>
</head>
<body style="margin:0">

<div style="position:absolute;overflow:auto;top:100px;bottom:100px;width:100%">

  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam a quam arcu. Duis ultrices mollis nibh ut hendrerit. Etiam a interdum metus. Integer volutpat, nibh laoreet euismod suscipit, libero sem iaculis lorem, ut hendrerit magna orci eu elit. Nulla eu ultricies libero. Nulla facilisi. Maecenas nec turpis vitae magna lobortis ornare sit amet ut lacus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc vestibulum lobortis orci, sit amet ornare dui congue nec. Morbi id magna at turpis auctor ultricies. Ut rhoncus quam augue, ut consectetur risus.</p>
  <div style="position:relative;background:red;">relative box<br>moves slower than the other text</div>
  <p>Fusce congue orci a nunc gravida sed pretium lorem convallis. Etiam hendrerit, ligula eget lobortis vestibulum, arcu sapien pharetra magna, auctor suscipit nisl tellus quis lacus. Cras id elit at ante mollis venenatis. Donec eu sollicitudin odio. Aliquam erat volutpat. Cras et tortor sed mi faucibus sagittis non quis metus. Morbi mauris ante, posuere vel rutrum id, mattis id enim. Morbi purus quam, euismod facilisis blandit quis, commodo at justo. Aliquam in fermentum nibh. Curabitur pharetra blandit risus sit amet tristique. Suspendisse potenti. Curabitur interdum eleifend justo, et dapibus justo volutpat sed.</p>          
  <div style="overflow:auto">
    <table>
      <tr><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th>    <th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th><th>test</th>    <th>test</th><th>test</th><th>test</th><th>test</th><th>test</th></tr>
      <tr><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td>    <td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td><td>test</td>    <td>test</td><td>test</td><td>test</td><td>test</td><td>test</td></tr>
    </table>
  </div>

</div>
</body>
</html>

起初似乎可以工作,但表格和其他一些元素仍然很卡顿。即使我将其应用于 #topdiv > * ,表格仍然很卡顿。也许有解决方案,但我会选择使用 transform 解决方案。 - Thomas

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