移动Webkit重排问题

时间:2012-07-02 16:31:04

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

我在webkit的移动版本中遇到了一个问题(特别是iOS 5.1.1上的Webkit 534.46作为移动版Safari,现在是iOS版Chrome),这在我见过的任何桌面浏览器上都没有。 (即以下演示应在移动版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重新滚动滚动(使用限制,直到滚动后100ms才能发生这种情况),这似乎解决了这个简单示例中的问题。不幸的是,这对这个问题的真实版本没有帮助。

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

我的问题是这里发生了什么,是否有一个我缺少的CSS解决方法?具体来说,我很好奇是否有任何CSS大师可以弄清楚布局情况是什么阻止了点击从击中固定元素上的正确位置?更好的理解可能有助于找到真正的解决方案。

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

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

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

5 个答案:

答案 0 :(得分:9)

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

基本上,增加了一个高于身体的普通div。当它被移除时,它会使身体有效地滚动或回流。在添加/删除之间将延迟设置为0ms足以允许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);

答案 1 :(得分:6)

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

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);
};

关于这一点的好处是它不需要创建/添加/删除元素,只需调整容器。

答案 2 :(得分:2)

看起来这是known bug

  

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

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

答案 3 :(得分:2)

我的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。

答案 4 :(得分:0)

我相信这样做会更好,并达到相同的效果,允许链接在固定页脚中可点击。不知何故,做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);
            });
        }