Подтвердить что ты не робот

Проблема с оплатой мобильного Webkit

У меня возникла проблема в мобильных версиях webkit (в частности, Webkit 534.46 на iOS 5.1.1 в качестве мобильного Safari, а теперь и Chrome для iOS), чего не наблюдается ни на одном настольном браузере, который я видел. (т.е. демонстрации ниже должны быть просмотрены на мобильной версии webkit.)

Вот живой пример проблемы. Ядро CSS очень прямолинейно. Он позиционирует алфавитный указатель слева от страницы:

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

Проблема возникает, когда элемент фиксируется по верхней части тела. Он может взаимодействовать с ним до тех пор, пока свиток не изменится, а затем перестанет принимать входные данные. Если я (вручную) перетащил прокрутку даже на один пиксель, тогда он снова активируется. Пример был как можно более простым и не использует JavaScript. После того, как он действительно ударил, я обнаружил, что кажется, что элемент считает, что он прокручивается, но визуально фиксируется. Другими словами, если вы нажмете "A", попробуйте снова нажать "A", иногда вы получите второй щелчок, но он будет дальше по списку. Мне показалось, что это проблема с оплатой CSS. Я знаю, что мобильный веб-кит пытается уменьшить количество переходов.

Вот живой пример обходного пути.

Я могу использовать JS, чтобы заставить CSS всего документа переливаться на прокрутку (с дроссельной заслонкой, которая предотвращает ее до 100 мс после прокрутки), которая, кажется, обходит эту проблему в простом примере. К сожалению, это не помогает реальной версии этой проблемы.

Это код для страницы проблемы и обходной путь script.

Мой вопрос заключается в том, что происходит здесь, и есть ли обходное решение CSS, которое мне не хватает? В частности, мне любопытно, может ли какой-либо гуру CSS понять, что такое макетная ситуация, которая предотвращает клики от попадания правильного места на фиксированный элемент? Лучшее понимание может помочь найти реальное решение.

Изменить: Я забыл упомянуть, что пример явно заставляет viewport размер окна. Таким образом, пользователь не может увеличивать/уменьшать масштаб, что означает, что фиксированное положение должно привязывать элемент к левой стороне окна.

Обновление (2012-09-20): Это, похоже, исправлено в Mobile Safari на iOS 6 (а также в UIWebView). Любое обходное решение должно сначала проверить, чтобы убедиться, что оно находится на iOS < 6. Например, используя CssUserAgent, это будет выглядеть так:

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

Ответ 1

Ответ, который фактически решил мою конкретную проблему, был вариантом решения, найденного в одной из ссылок @Paul Sweatte:

По существу, добавляется простой div, который выше тела. Когда он удаляется, он заставляет тело эффективно прокручивать или переплавлять. Установка задержки на 0мс между добавлением/удалением достаточно, чтобы позволить DOM пересчитать, не вызывая какого-либо мерцания. Это был минимальный script, который я мог найти, который полностью решил проблему для всех элементов position:fixed на моем конкретном экземпляре этой проблемы.

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

Ответ 2

По иронии судьбы, мое первоначальное исправление исправления (связанное с вопросом) теперь работает и в моем реальном приложении. Ввод его варианта здесь в случае полезен для кого-то еще. Он может быть вызван любым элементом контейнера, или если в нем ничего не передается, он обрабатывает весь документ.

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

Хорошая вещь в том, что она не требует создания/добавления/удаления элементов, просто настраивая контейнер.

Ответ 3

Похоже, что это известная ошибка:

Основная проблема: если страница движется программно (т.е. пользователь не вызывал прокрутку), элементы внутри элемента fix недоступны.

Используйте абсолютное позиционирование, изменить разметку или использовать один из гибридных обходных путей.

Ответ 4

Моя установка iWebInspector довольно разорена прямо сейчас, но после беспорядка с jsfiddle и iOS sim кажется, что ваша догадка правильная - несмотря на то, что позиция фиксированная, браузер считает, что страница прокручивается и закручивает щелчок цели.

Похоже, что это та же проблема, что и iOS Safari: привязки в фиксированном позиционном элементе работают только один раз, который также не был решен с помощью чистого CSS. Связано также: Фиксированная позиция navbar, доступная только один раз в Mobile Safari на iOS5.

Тангенциально, и я уверен, что это уже было замечено, невозможно прокручивать левую сторону, поэтому на iPhone индекс показывает только A-M.

Ответ 5

Я считаю, что это лучше, и достигает такого же эффекта, позволяя ссылки кликать в фиксированных нижних колонтитулах. Каким-то образом, скрытие 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);
            });
        }

Ответ 6

Вот вариант обхода McKamey. Он избегает перепланировки дважды и может помочь с мерцанием (в зависимости от вашего приложения):

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