фиксированное положение div зависает на странице (iPad)



У меня есть asp.net веб-сайт, который я создаю, будет поддерживаться на ipad. Когда я сосредотачиваюсь на элементе ввода и клавиатура всплывает, заголовок div с фиксированной позицией(который обычно прокручивается вместе со страницей) всплывает на странице на расстояние, эквивалентное количеству, которое занимает клавиатура, и застывает там на время процесса ввода. Как только клавиатура опускается обратно, div защелкивается на месте и снова ведет себя нормально. Я тестирую на iOS5, поэтому позиция: fixed должна быть поддерживаемый.



Это известная проблема? Кто-нибудь сталкивался с этим раньше и имел с этим дело? Я, кажется, ничего не могу найти по этому поводу.

523   2  

2 ответов:

Фиксированное позиционирование нарушено на iOS5/iOS6 / iOS7.

Правка 3: смотрите ссылку на рабочее исправление в конце этого ответа для iOS8.

Положение: фиксированное нарушается, когда либо:

A) страница увеличена

Или

B) клавиатура отображается на iPad / iPhone (из-за ввода, получающего фокус).

Вы можете просмотреть ошибки самостоятельно в jsbin.com/icibaz/3 путем открытия ссылки и масштабирования, или придания фокуса ввода. Вы можете редактировать редактировать html себе.

Примечания об ошибках (а) и (Б):

  1. Фиксированный div с top: 0px; left: 0px; будет отображаться в неправильном положении (выше или ниже верхней части экрана), когда ввод получает фокус и клавиатура показывает.

  2. Проблема, по-видимому, связана с автоцентрированием ввода на экране (изменение окна.pageYOffset).

  3. Похоже, это ошибка вычисления, а не перерисовки: если вы заставите top: измениться (например, переключение между 0px и 1px) в событии onScroll вы можете увидеть, как фиксированный div перемещается на пиксель, но он остается в неправильном месте.

  4. Одно из решений, которое я использовал ранее, состоит в том, чтобы скрыть фиксированный div, когда вход получает фокус - см. другой ответ, который я написал.

  5. Фиксированный div, кажется, застревает в том же абсолютном положении на странице, в котором он был в момент открытия клавиатуры.

  6. Поэтому, возможно, измените div на абсолютное позиционирование, когда вход имеет фокус? Правка 3: см. комментарий внизу с использованием этого решения. Или, возможно, сохраните значения pageXOffset/pageYOffset перед открытием клавиатуры и в событии onScroll вычислите разницу между этими значениями и текущими значениями pageXOffset/pageYOffset (текущими после открытия клавиатуры) и компенсируйте фиксированный div этой разницей.

  7. Кажется, есть другая проблема с фиксированным позиционированием, если страница масштабируется-попробуйте здесь (Также хорошо информация здесь о поддержке Android для fixed в комментариях).

Edit 1: для воспроизведения используйте jsbin (не jsfiddle) и используйте полноэкранный режим jsbin (не страницу редактирования). Избегайте jsfiddle (и редактировать представление jsbin), потому что они помещают код внутри iframe, который вызывает помехи с фиксированным позиционированием и pageYOffset.

Edit 2: iOS 6 и iOS 7 Mobile Safari position:fixed; по - прежнему имеют те же проблемы-предположительно, они по дизайну!.

Правка 3: рабочий решение для (b) заключается в том, что когда входные данные получают фокус, измените заголовок на абсолютное позиционирование, а затем установите верхний заголовок на событии прокрутки страницы , например. Это решение:

  • использует фиксированное позиционирование, когда вход не сфокусирован (используя окно.onscroll имеет ужасное дрожание).
  • не допускайте Пинч-Зума (избегайте ошибки (а) выше).
  • использует абсолютное позиционирование и окно.pageYOffset после того, как вход получает фокус (так что заголовок правильно расположен).
  • если прокрутить пока ввод имеет фокус, установите стиль.top to equal pageYOffset (заголовок будет немного дрожать из-за задержки события onscroll даже на iOS8).
  • при использовании UIWebView в приложении на iOS8 или при использовании
  • вернитесь к заголовку фиксированной позиции, как только ввод теряет фокус (пример использует ввод.онблур, но, вероятно, тидер, чтобы использовать документ.тело.ОНФ).
  • остерегайтесь ошибки юзабилити что если заголовок слишком большой, вход может быть закрыт / закрыт.
  • я не мог работать для нижнего колонтитула из-за ошибок в высоте страницы/окна просмотра iOS, когда клавиатура показывает.
  • изменить примеру используя http://jsbin.com/xujofoze/4/edit и просматривать с помощью http://output.jsbin.com/xujofoze/4/quiet

Для моих нужд мне было проще использовать абсолютный позиционированный заголовок, скрывать его перед прокруткой и показывать при завершении прокрутки (мне нужен тот же код для поддержки iOS4 и Android).

Для моих целей я скрываю заголовок на событии touchstart и показываю его снова на событии touchend или scroll (плюс некоторые таймеры для улучшения отзывчивости/уменьшения мерцания). Он вспыхивает, но это лучший компромисс, который я мог найти. Можно обнаружить начало прокрутки с помощью события touchmove (это делает jQuery), но я найденный touchmove не сработал так же хорошо для меня, потому что:

  1. Регулярно iPad не может сделать перерисовку перед прокруткой (т. е. абсолютный заголовок остается застрявшим - даже если top был изменен перед началом прокрутки).

  2. Когда элемент ввода получает фокус, iPad автоматически центрирует элемент, но событие scrollstart не срабатывает (потому что нет touchmove, если просто clicking вход).

Реализация фиксированного заголовка на iOS5 может быть улучшено за счет использования гибридного подхода фиксированного и абсолютного позиционирования:

  • Используется фиксированное позиционирование для iOS5, пока вход не получит фокус.

  • Когда входной сигнал получает фокус (показ клавиатуры), измените на абсолютный код позиционирования iOS4.

  • Когда клавиатура закрыта, вернитесь к фиксированному положению.

Код для определения того, когда клавиатура закрыта (например, с помощью клавиши скрытия клавиатуры), должен зарегистрировать событие DOMFocusOut на document элемент и сделать что-то вроде следующего кода. Тайм-аут необходим, потому что событие DOMFocusOut может сработать между тем, когда один элемент получает фокус, а другой теряет его.

function document_DOMFocusOut() {
    clearTimeout(touchBlurTimer);
    touchBlurTimer = setTimeout(function() {
        if (document.activeElement == document.body) {
            handleKeyboardHide();
        }
    }.bind(this), 400);
}

Мой фиксированный код заголовка выглядит примерно так:

{
    setup: function() {
        observe(window, 'scroll', this, 'onWinScroll');
        observe(document, 'touchstart', this, 'onTouchStart');
        observe(document, 'touchend', this, 'onTouchEnd');
        if (isMobile) {
            observe(document, 'DOMFocusOut', this, 'docBlurTouch');
        } else if (isIE) {
        // see http://ajaxian.com/archives/fixing-loss-of-focus-on-ie for code to go into this.docBlurIe()
            observe(document, 'focusout', this, 'docBlurIe');
        } else {
            observe(isFirefox ? document : window, 'blur', this, 'docBlur');
        }
    },

    onWinScroll: function() {
        clearTimeout(this.scrollTimer);
        this.scrolling = false;
        this.rehomeAll();
    },

    rehomeAll: function() {
        if ((isIOS5 && this.scrolling) || isIOS4 || isAndroid) {
            this.useAbsolutePositioning();
        } else {
            this.useFixedPositioning();
        }
    },

    // Important side effect that this event registered on document on iOs. Without it event.touches.length is incorrect for any elements in the document using the touchstart event!!!
    onTouchStart: function(event) {
        clearTimeout(this.scrollTimer);
        if (!this.scrolling && event.touches.length == 1) {
            this.scrolling = true;
            this.touchStartTime = inputOrOtherKeyboardShowingElement(event.target) ? 0 : (new Date).getTime();
            // Needs to be in touchStart so happens before iPad automatic scrolling to input, also not reliable using touchMove (although jQuery touch uses touchMove to unreliably detect scrolling).
            this.rehomeAll();
        }
    },

    onTouchEnd: function(event) {
        clearTimeout(this.scrollTimer);
        if (this.scrolling && !event.touches.length) {
            var touchedDuration = (new Date).getTime() - this.touchStartTime;
            // Need delay so iPad can scroll to the input before we reshow the header.
            var showQuick = this.touchStartTime && touchedDuration < 400;
            this.scrollTimer = setTimeout(function() {
                if (this.scrolling) {
                    this.scrolling = false;
                    this.rehomeAll();
                }
            }.bind(this), showQuick ? 0 : 400);
        }
    },

    // ... more code
}

JQuery mobile поддерживает события scrollstart и scrollstop:

var supportTouch = $.support.touch,
    scrollEvent = "touchmove scroll",
    touchStartEvent = supportTouch ? "touchstart" : "mousedown",
    touchStopEvent = supportTouch ? "touchend" : "mouseup",
    touchMoveEvent = supportTouch ? "touchmove" : "mousemove";

function triggerCustomEvent( obj, eventType, event ) {
    var originalType = event.type;
    event.type = eventType;
    $.event.handle.call( obj, event );
    event.type = originalType;
}

// also handles scrollstop
$.event.special.scrollstart = {

    enabled: true,

    setup: function() {

        var thisObject = this,
            $this = $( thisObject ),
            scrolling,
            timer;

        function trigger( event, state ) {
            scrolling = state;
            triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
        }

        // iPhone triggers scroll after a small delay; use touchmove instead
        $this.bind( scrollEvent, function( event ) {

            if ( !$.event.special.scrollstart.enabled ) {
                return;
            }

            if ( !scrolling ) {
                trigger( event, true );
            }

            clearTimeout( timer );
            timer = setTimeout(function() {
                trigger( event, false );
            }, 50 );
        });
    }
};

Comments

    Ничего не найдено.