【问题标题】:Mobile Webkit reflow issue移动 Webkit 回流问题
【发布时间】:2012-07-03 02:26:17
【问题描述】:

我在 webkit 的移动版本(特别是 iOS 5.1.1 上的 Webkit 534.46 作为移动 Safari,现在是 Chrome for iOS)中遇到了一个问题,这在我见过的任何桌面浏览器上都没有发生。 (即下面的演示应在移动版 webkit 上查看。)

Here is a live example of the issue. CSS 的核心非常简单。它在页面左侧放置一个字母索引:

#index {
    left:0; margin:0; padding:0; position:fixed; top:0; width:3em;
}

当元素固定在主体顶部上方时会出现此问题。它完全能够与之交互,直到滚动发生变化,然后它停止接受输入。如果我(手动)摇动滚动甚至一个像素,那么它会再次变为活动状态。该示例尽可能简单,不使用任何 JavaScript。在真正敲定它之后,我发现该元素似乎认为它是滚动的,但在视觉上是固定的。换句话说,如果您单击“A”然后尝试再次单击“A”,有时您会再次单击,但它会在列表的下方。这对我来说似乎是一个 CSS 重排问题。我知道移动 webkit 试图减少回流的次数。

Here is a live example of the workaround.

我可以使用 JS 来强制整个文档的 CSS 在滚动时重排(使用节流阀防止它在滚动后 100 毫秒内发生),这在简单示例中似乎解决了这个问题。不幸的是,这对这个问题的真实世界版本没有帮助。

This is the code for the issue page and the workaround script.

我的问题是这里发生了什么,是否有我遗漏的 CSS 解决方法? 具体来说,我很好奇是否有任何 CSS 专家可以找出阻止点击的布局情况从击中固定元素的正确位置?更好地理解可能有助于找到真正的解决方法。

编辑:我忘了提到该示例明确地将视口强制为窗口大小。因此用户无法放大/缩小,这意味着 position:fixed 应该将元素锚定到窗口的左侧。

更新 (2012-09-20): 这似乎已在 iOS 6 上的 Mobile Safari(以及 UIWebView)中得到修复。任何解决方法都应首先检查以确保它在 iOS CssUserAgent 这看起来像:

if (parseFloat(cssua.ua.ios) < 6) { /* ... */ }

【问题讨论】:

  • 我仍在通过两个答案中的各种解决方法来找到“最佳”。我给你们两个链接+1。我会将赏金奖励给真正解决我的问题的人。谢谢!
  • 我仍在寻找适用于我的特定情况的解决方案,但赏金窗口即将用完,所以我将把它奖励给@Paul Sweatte,因为他首先回答并且他的链接有更多的解决方案变化。谢谢大家!

标签: css webkit touch css-position mobile-webkit


【解决方案1】:

我相信这样更好,并且可以达到相同的效果,允许在固定页脚中点击链接。不知何故,隐藏 urlbar 会导致固定页脚中的链接无法点击,直到您滚动一点。我在聚焦输入时也看到了这一点,并且我将一个事件处理程序附加到所有聚焦事件以触发它。我使用 dojo 执行此操作以附加事件。

        if(navigator.userAgent.match(/iPhone/i)){
        /* The famous iOS can't-click-links until touch fix, I attach onfocus */
            query('input,textarea,select', this.domNode).on('focus', function(el){
                document.documentElement.style.paddingRight = '1px';
                setTimeout(function () {
                document.documentElement.style.paddingRight = '';
                }, 0);
            });
        }

【讨论】:

  • 比什么好?它与my original 的解决方案相同,但具有硬编码值。需要做的是强制回流。
【解决方案2】:

这是 McKamey 解决方法的一种变体。它避免了两次回流,并且可能有助于闪烁(取决于您的应用):

setTimeout(function(){
    document.body.style.borderBottom = 
        document.body.style.borderBottom === 'none' ? '1px solid white' : 'none';
}, 0);

【讨论】:

  • 您还不需要删除白线(尤其是在非白色背景上)吗?那将是您的第二次回流。
  • 您可以在非白色背景上将颜色设置为透明,以避免二次回流。
【解决方案3】:

具有讽刺意味的是,我最初的回流修复(链接到问题中)现在也可以在我的真实应用程序中使用。将它的变体放在这里以防万一对其他人有用。它可以在任何容器元素上调用,或者如果没有传入任何内容,它会重排整个文档。

var forceReflow = function(elem){
    elem = elem || document.documentElement;

    // force a reflow by increasing size 1px
    var width = elem.style.width,
        px = elem.offsetWidth+1;

    elem.style.width = px+'px';

    setTimeout(function(){
        // undo resize, unfortunately forces another reflow
        elem.style.width = width;
        elem = null;
    }, 0);
};

这样做的好处是它不需要创建/添加/删除元素,只需调整容器即可。

【讨论】:

  • 你知道如何防止在回流之前显示损坏的内容吗?它会在很短的时间内(约 50 毫秒)可见,但对用户来说很明显。
  • 即使setTimeout 使用0 的值,您是否看到损坏的内容?如果是这样,您可能需要进行一般优化以提高页面的呈现速度。 Try some of the suggestions here. 通常我看到的是人们使用 jQuery 就绪事件来构建他们的 UI,这很慢。
  • IIRC,向元素添加一个虚拟类(例如,'foo' + Date.now())应该会导致回流,并且您不需要删除该类(除非您关心整洁)。
【解决方案4】:

真正解决我的特定问题的答案是找到的解决方案的变体in one of @Paul Sweatte's links

本质上,添加了一个比 body 高的普通 div。当它被移除时,它会导致正文有效地滚动或重排。将添加/删除之间的延迟设置为 0 毫秒就足以让 DOM 重新计算而不会导致任何闪烁。这是我能找到的最小脚本,它完全解决了这个问题我的特定实例上所有position:fixed元素的问题。

var hack = document.createElement("div");
hack.style.height = "101%";
document.body.appendChild(hack);
setTimeout(function(){
    document.body.removeChild(hack);
    hack = null;
}, 0);

【讨论】:

    【解决方案5】:

    看起来这是known bug

    核心问题是:如果页面以编程方式移动(即用户没有引起滚动),则修复元素内的元素不可用。

    使用绝对定位,change the markup,或使用混合workarounds之一。

    【讨论】:

    • 请注意,我专门发布的示例不使用 JavaScript 滚动。所以这纯粹是一个 CSS 问题。
    【解决方案6】:

    我的 iWebInspector 安装现在非常失败,但是在弄乱了 jsfiddle 和 iOS sim 之后,你的预感似乎是正确的 - 尽管位置:固定,浏览器认为页面已经滚动,并搞砸了点击目标。

    这看起来很像iOS Safari: Anchors within a fixed positioned element only work once 的问题,纯 CSS 也没有解决这个问题。也相关:Fixed position navbar only clickable once in Mobile Safari on iOS5

    切线,我敢肯定它已经被注意到了,不可能滚动左侧,所以在 iPhone 上,索引只显示 A-M。

    【讨论】:

    • 谢谢。是的,我没有费心制作左侧响应式布局,我尝试删除与错误无关的所有内容。
    猜你喜欢
    • 1970-01-01
    • 2015-08-09
    • 2013-03-18
    • 1970-01-01
    • 1970-01-01
    • 2013-09-15
    • 2013-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多