Фиксированное позиционирование iOS 5 и виртуальная клавиатура

У меня есть мобильный веб-сайт, у которого есть div, прикрепленный к нижней части экрана через фиксированное положение. Все работает отлично в iOS 5 (я тестирую на iPod Touch), пока не нахожусь на странице с формой. Когда я вхожу в поле ввода и появляется виртуальная клавиатура, внезапно фиксированное положение моего div теряется. Теперь div теперь прокручивается со страницы, пока клавиатура видна. Как только я нажимаю "Готово", чтобы закрыть клавиатуру, div возвращается в свое положение в нижней части экрана и подчиняется положению: фиксированное правило.

Кто-нибудь еще испытывал такое поведение? Ожидается ли это? Спасибо.

Ответ 1

У меня была эта проблема в моем приложении. Вот как я работаю над этим:

input.on('focus', function(){
    header.css({position:'absolute'});
});
input.on('blur', function(){
    header.css({position:'fixed'});
});

Я просто прокручиваю вверх и позиционирую его там, поэтому пользователь iOS не замечает ничего странного. Оберните это при обнаружении какого-либо пользователя, чтобы другие пользователи не получали этого поведения.

Ответ 2

У меня была немного другая проблема с ipad, когда виртуальная клавиатура подтолкнула мое окно просмотра к экрану. Затем, после того как пользователь закрыл виртуальную клавиатуру, мой видовой экран был все еще вне экрана. В моем случае я сделал что-то вроде следующего:

var el = document.getElementById('someInputElement');
function blurInput() {
    window.scrollTo(0, 0);
}
el.addEventListener('blur', blurInput, false);

Ответ 3

Это код, который мы используем для исправления проблемы с ipad. Он в основном обнаруживает несоответствия между положением смещения и прокрутки, что означает, что "исправлено" работает неправильно.

$(window).bind('scroll', function () {
    var $nav = $(".navbar")
    var scrollTop = $(window).scrollTop();
    var offsetTop = $nav.offset().top;

    if (Math.abs(scrollTop - offsetTop) > 1) {
        $nav.css('position', 'absolute');
        setTimeout(function(){
            $nav.css('position', 'fixed');
        }, 1);
    }
});

Ответ 4

Позиционные фиксированные элементы просто не обновляют свое положение, когда клавиатура вставлена. Я обнаружил, что, обманывая Safari, полагая, что страница изменилась, элементы будут перегруппироваться. Это не идеально, но по крайней мере вам не нужно беспокоиться о переходе на "положение: абсолютное" и отслеживание изменений самостоятельно.

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

    var needsScrollUpdate = false;
    $(document).scroll(function(){
        if(needsScrollUpdate) {
            setTimeout(function() {
                $("body").css("height", "+=1").css("height", "-=1");
            }, 0);
        }
    });
    $("input, textarea").live("focus", function(e) {
        needsScrollUpdate = true;
    });

    $("input, textarea").live("blur", function(e) {
        needsScrollUpdate = false;
    });

Ответ 5

На всякий случай кто-то случается на этой теме, как я это делал, исследуя эту проблему. Я нашел эту ветку полезной для стимулирования моего мышления по этому вопросу.

Это было мое решение для этого в недавнем проекте. Вам просто нужно изменить значение "targetElem" на селектор jQuery, который представляет ваш заголовок.

if(navigator.userAgent.match(/iPad/i) != null){

var iOSKeyboardFix = {
      targetElem: $('#fooSelector'),
      init: (function(){
        $("input, textarea").on("focus", function() {
          iOSKeyboardFix.bind();
        });
      })(),

      bind: function(){
            $(document).on('scroll', iOSKeyboardFix.react);  
                 iOSKeyboardFix.react();      
      },

      react: function(){

              var offsetX  = iOSKeyboardFix.targetElem.offset().top;
              var scrollX = $(window).scrollTop();
              var changeX = offsetX - scrollX; 

              iOSKeyboardFix.targetElem.css({'position': 'fixed', 'top' : '-'+changeX+'px'});

              $('input, textarea').on('blur', iOSKeyboardFix.undo);

              $(document).on('touchstart', iOSKeyboardFix.undo);
      },

      undo: function(){

          iOSKeyboardFix.targetElem.removeAttr('style');
          document.activeElement.blur();
          $(document).off('scroll',iOSKeyboardFix.react);
          $(document).off('touchstart', iOSKeyboardFix.undo);
          $('input, textarea').off('blur', iOSKeyboardFix.undo);
      }
};

};

Есть немного задержки в фиксации, потому что iOS останавливает манипуляции с DOM во время прокрутки, но это делает трюк...

Ответ 6

Ни один из других ответов, которые я нашел для этой ошибки, не работал у меня. Я смог исправить это просто, прокрутив страницу назад на 34 пикселя, количество мобильных сафари прокручивает ее вниз. с jquery:

$('.search-form').on('focusin', function(){
    $(window).scrollTop($(window).scrollTop() + 34);
});

Это, очевидно, вступит в силу во всех браузерах, но предотвратит его нарушение в iOS.

Ответ 7

Эта проблема действительно раздражает.

Я объединил некоторые из вышеупомянутых методов и придумал следующее:

$(document).on('focus', 'input, textarea', function() {
    $('.YOUR-FIXED-DIV').css('position', 'static');
});

$(document).on('blur', 'input, textarea', function() {
    setTimeout(function() {
        $('.YOUR-FIXED-DIV').css('position', 'fixed');
        $('body').css('height', '+=1').css('height', '-=1');
    }, 100);
});

У меня есть два фиксированных навигатора (верхний и нижний колонтитулы, используя twitter bootstrap). Оба были странными, когда клавиатура встала и снова странно, когда клавиатура опущена.

С этим временным/отложенным исправлением это работает. Я все еще нахожусь сбой раз в то время, но он кажется достаточно хорошим, чтобы показать его клиенту.

Сообщите мне, если это сработает для вас. Если нет, мы можем найти что-то еще. Спасибо.

Ответ 8

Я взял Jory Cunningham ответ и улучшил его:

Во многих случаях это не только один элемент, который сходит с ума, но и несколько фиксированных позиционированных элементов, поэтому в этом случае targetElem должен быть объектом jQuery, который имеет все фиксированные элементы, которые вы хотите "исправить". Хо, это похоже на то, чтобы клавиатура iOS исчезла, если вы прокрутите...

Разумеется, вы должны использовать это событие ПОСЛЕ document DOM ready или непосредственно перед закрывающим тегом </body>.

(function(){
    var targetElem = $('.fixedElement'), // or more than one
        $doc       = $(document),
        offsetY, scrollY, changeY;

    if( !targetElem.length || !navigator.userAgent.match(/iPhone|iPad|iPod/i) )
        return;

    $doc.on('focus.iOSKeyboardFix', 'input, textarea, [contenteditable]', bind);

    function bind(){
        $(window).on('scroll.iOSKeyboardFix', react);
        react();
    }

    function react(){
        offsetY = targetElem.offset().top;
        scrollY = $(window).scrollTop();
        changeY = offsetY - scrollY;

        targetElem.css({'top':'-'+ changeY +'px'});

        // Instead of the above, I personally just do:
        // targetElem.css('opacity', 0);

        $doc.on('blur.iOSKeyboardFix', 'input, textarea, [contenteditable]', unbind)
            .on('touchend.iOSKeyboardFix', unbind);
    }

    function unbind(){
        targetElem.removeAttr('style');
        document.activeElement.blur();

        $(window).off('scroll.iOSKeyboardFix');
        $doc.off('touchend.iOSKeyboardFix blur.iOSKeyboardFix');
    }
})();

Ответ 9

У меня была проблема с iOS7. Нижние фиксированные элементы испортили бы мой взгляд, не сфокусировавшись должным образом.

Все начали работать, когда я добавил этот метатег в свой html.

<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no,height=device-height" >

Часть, которая сделала разницу:

height=device-height

Надеюсь, что это поможет кому-то.

Ответ 10

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

У меня есть эта точная проблема с моим фиксированным заголовком на [УДАЛЕНО]. Прокрутите страницу вниз, затем нажмите на поле поиска и удалите... макет сломан. Я даже пытался исправить это, вернувшись к абсолютному позиционированию на фокусном событии, которое работает, но затем я теряю фокус (клавиатура остается открытой, но курсор больше не находится в окне поиска).

В любом случае я работаю над этим, поэтому я дам вам знать, сортирую ли я его

Приветствия

Ответ 11

У меня есть решение, подобное @NealJMD, кроме моего только для iOS и правильно определяет смещение прокрутки, измеряя scollTop до и после прокрутки собственной клавиатуры, а также используя setTimeout, чтобы разрешить естественную прокрутку:

var $window = $(window);
var initialScroll = $window.scrollTop();
if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
  setTimeout(function () {
    $window.scrollTop($window.scrollTop() + (initialScroll - $window.scrollTop()));
  }, 0);
}

Ответ 12

Я установил фиксированное положение основного места размещения Ipad таким образом:

var mainHeight;
var main = $('.main');

// hack to detects the virtual keyboard close action and fix the layout bug of fixed elements not being re-flowed
function mainHeightChanged() {
    $('body').scrollTop(0);
}

window.setInterval(function () {
    if (mainHeight !== main.height())mainHeightChanged();
    mainHeight = main.height();
}, 100);

Ответ 13

У меня была аналогичная проблема с @ds111 s. Мой сайт был подтолкнут клавиатурой, но не закрылся, когда клавиатура закрылась.

Сначала я попробовал решение @ds111, но у меня было два поля input. Конечно, сначала клавиатура уходит, затем размывается (или что-то в этом роде). Таким образом, второй input находился под клавиатурой, когда фокус переключился непосредственно с одного входа на другой.

Кроме того, "прыжок вверх" был недостаточно хорош для меня, поскольку вся страница имеет размер ipad. Поэтому я сделал прокрутку гладкой.

Наконец, мне пришлось прикрепить прослушиватель событий ко всем входам, даже тем, которые были в данный момент скрыты, следовательно, live.

Все вместе я могу объяснить следующий фрагмент javascript как: Прикрепите следующий прослушиватель событий размытия к текущему и будущему input и textarea (= ​​live): Подождите льготный период (= window.setTimeout(..., 10)) и плавно прокрутите вверх (= animate({scrollTop: 0}, ...)), но только если "нет клавиатуры" (= if($('input:focus, textarea:focus').length == 0)).

$('input, textarea').live('blur', function(event) {
    window.setTimeout(function() {
        if($('input:focus, textarea:focus').length == 0) {
            $("html, body").animate({ scrollTop: 0 }, 400);
        }
    }, 10)
})

Помните, что период отсрочки (= 10) может быть слишком коротким или клавиатура может отображаться, хотя не фокусируется input или textarea. Конечно, если вы хотите, чтобы прокрутка выполнялась быстрее или медленнее, вы можете настроить продолжительность (= 400)

Ответ 14

действительно много работал, чтобы найти это обходное решение, которое вкратце рассматривает фокус и размытие событий на входах, а также прокрутку для выборочного изменения положения фиксированной полосы при возникновении событий. Это пуленепробиваемый и охватывает все случаи (перемещение с помощью кнопки <, > , прокрутки, прокрутки). Примечание id = "nav" - мой фиксированный нижний div. Вы можете легко перенести это на стандартные js или jquery. Это dojo для тех, кто использует электроинструменты; -)

определить ([    "dojo/​​готов",    "dojo/​​запрос", ], функция (готово, запрос) {

ready(function(){

    /* This addresses the dreaded "fixed footer floating when focusing inputs and keybard is shown" on iphone 
     * 
     */
    if(navigator.userAgent.match(/iPhone/i)){
        var allInputs = query('input,textarea,select');
        var d = document, navEl = "nav";
        allInputs.on('focus', function(el){
             d.getElementById(navEl).style.position = "static";
        });

        var fixFooter = function(){
            if(d.activeElement.tagName == "BODY"){
                d.getElementById(navEl).style.position = "fixed";
            }
        };
        allInputs.on('blur', fixFooter);
        var b = d.body;
        b.addEventListener("touchend", fixFooter );
    }

});

});//end define

Ответ 15

Это сложная проблема, чтобы получить "право". Вы можете попытаться скрыть нижний колонтитул на фокусе элемента ввода и показать размытие, но это не всегда надежно на iOS. Каждый раз так часто (один раз в десять, скажем, на моем iPhone 4S) фокусное событие, похоже, не срабатывает (или, может быть, есть состояние гонки), а нижний колонтитул не скрывается.

После долгих проб и ошибок я придумал это интересное решение:

<head>
    ...various JS and CSS imports...
    <script type="text/javascript">
        document.write( '<style>#footer{visibility:hidden}@media(min-height:' + ($( window ).height() - 10) + 'px){#footer{visibility:visible}}</style>' );
    </script>
</head>

По существу: используйте JavaScript для определения высоты окна устройства, а затем динамически создайте мультимедийный запрос CSS, чтобы скрыть нижний колонтитул, когда высота окна уменьшается на 10 пикселей. Поскольку открытие клавиатуры изменяет размер экрана браузера, это никогда не прерывается в iOS. Поскольку он использует механизм CSS, а не JavaScript, он намного быстрее и плавнее!

Примечание. Я обнаружил, что "видимость: скрытая" менее глючная, чем "display: none" или "position: static", но ваш пробег может отличаться.

Ответ 16

Работает для меня

if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
    $(document).on('focus', 'input, textarea', function() {
        $('header').css({'position':'static'});
    });
    $(document).on('blur', 'input, textarea', function() {
        $('header').css({'position':'fixed'});
    });
}

Ответ 17

В нашем случае это будет исправляться, как только пользователь прокручивается. Итак, это исправление, которое мы использовали для симуляции прокрутки на blur на любых input или textarea:

$(document).on('blur', 'input, textarea', function () {
    setTimeout(function () {
        window.scrollTo(document.body.scrollLeft, document.body.scrollTop);
    }, 0);
});

Ответ 18

Отвечаю, что это невозможно.

Я вижу 25 ответов, но в моем случае никто не работает. То, что Yahoo и другие страницы скрывают фиксированный заголовок, когда клавиатура включена. И Bing превращает всю страницу без прокрутки (overflow-y: hidden).

Случаи, о которых говорилось выше, различны, некоторые имеют проблемы при прокрутке, некоторые - в фокусе или размытии. У некоторых есть фиксированный нижний колонтитул или заголовок. Я не могу проверить каждую комбинацию, но вы можете понять, что это невозможно сделать в вашем случае.

Ответ 19

Нашел это решение на Github.

https://github.com/Simbul/baker/issues/504#issuecomment-12821392

Убедитесь, что у вас есть прокручиваемый контент.

// put in your .js file
$(window).load(function(){
    window.scrollTo(0, 1);
});

// min-height set for scrollable content
<div id="wrap" style="min-height: 480px">
  // website goes here
</div>

Адресная строка складывается в качестве дополнительного бонуса.

Ответ 20

В случае, если кто-то захочет попробовать это. Я получил следующие работы для меня на фиксированном нижнем колонтитуле с полем ввода в нем.

<script>
    $('document').ready(
        function() {
            if (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)
                  || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i)) {
                var windowHeight = $(window).height();
                var documentHeight = $(document).height();

                $('#notes').live('focus', function() {
                    if (documentHeight > windowHeight) {
                        $('#controlsContainer').css({
                            position : 'absolute'
                        });
                        $("html, body").animate({
                            scrollTop : $(document).height()
                        }, 1);
                    }
                });
                $('#notes').live('blur', function() {
                    $('#controlsContainer').css({
                        position : 'fixed'
                    });
                    $("html, body").animate({
                        scrollTop : 0
                    }, 1);
                });
            }
        });
</script>

Ответ 21

У меня такая же проблема. Но я понял, что фиксированная позиция просто отложена и не сломана (по крайней мере для меня). Подождите 5-10 секунд и посмотрите, будет ли диверсия отрегулирована в нижней части экрана. Я считаю, что это не ошибка, а отложенный ответ, когда клавиатура открыта.

Ответ 22

Я пробовал все подходы из этой темы, но если они не помогли, они сделали еще хуже. В конце концов, я решил заставить устройство потерять фокус:

$(<selector to your input field>).focus(function(){
    var $this = $(this);
    if (<user agent target check>) {
        function removeFocus () {
            $(<selector to some different interactive element>).focus();
            $(window).off('resize', removeFocus);
        }
        $(window).on('resize', removeFocus);
    }
});

и он работал как шарм и фиксировал мою липкую форму входа.

Пожалуйста, ПРИМЕЧАНИЕ:

  • JS-код, приведенный выше, предназначен только для представления моей идеи, чтобы выполнить этот фрагмент, замените значения в angular скобках (< > ) соответствующими значениями для вашей ситуации.
  • Этот код предназначен для работы с jQuery v1.10.2

Ответ 23

Это все еще большая ошибка для любых HTML-страниц с более высокими модулями Bootstrap в iOS 8.3. Ни одно из предложенных выше решений не работало, и после увеличения масштаба в любом поле под суммой высокого модального режима Mobile Safari и/или WkWebView перемещали фиксированные элементы туда, где находился прокрутка тела HTML, оставляя их несогласованными там, где они на самом деле изложенных.

Чтобы обойти ошибку, добавьте прослушиватель событий к любому из ваших модальных входов, например:

$(select.modal).blur(function(){
  $('body').scrollTop(0);
});

Я предполагаю, что это работает, потому что заставляя высоту прокрутки тела HTML переустанавливает фактическое представление, где iOS 8 WebView ожидает, что фиксированное содержимое модального div будет.

Ответ 24

Если кто-то искал совершенно другой маршрут (например, вы даже не пытаетесь привязать этот "нижний колонтитул" к прокрутке, но вы просто хотите, чтобы div оставался внизу страницы), вы можете просто установить нижнее положение как относительное.

Это означает, что даже если виртуальная клавиатура появится в вашем мобильном браузере, ваш нижний колонтитул просто останется привязанным к нижней части страницы, не пытаясь реагировать на показ или закрытие виртуальной клавиатуры.

Очевидно, что на Safari лучше выглядеть, если позиция фиксирована, а нижний колонтитул следует за страницей при прокрутке вверх или вниз, но из-за этой странной ошибки в Chrome мы закончили переход к простому отношению нижнего колонтитула.

Ответ 25

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

$("#myInput").on("focus", function () {
    $("body").css("position", "fixed");
});

$("#myInput").on("blur", function () {
    $("body").css("position", "static");
});

Ответ 26

iOS9 - та же проблема.

TL;DR - источник проблемы. Для решения прокрутите вниз

У меня была форма в position:fixed iframe с id = 'subscribe-popup-frame'

В соответствии с исходным вопросом, при вводе фокуса iframe будет идти в верхней части документа, а не в верхней части экрана.

Та же проблема не возникала в режиме safari dev, когда пользовательский агент установлен в idevice. Таким образом, проблема возникает из-за виртуальной клавиатуры iOS, когда она появляется.

Я получил некоторую видимость в том, что происходило на консоли, регистрируя позицию iframe (например, $('#subscribe-popup-frame', window.parent.document).position()), и оттуда я мог видеть, что iOS, похоже, устанавливает положение элемента {top: -x, left: 0} при появлении виртуальной клавиатуры ( т.е. сосредоточен на входном элементе).

Итак, мое решение состояло в том, чтобы взять этот pesky -x, отменить знак, а затем использовать jQuery, чтобы добавить эту позицию top обратно в iframe. Если есть лучшее решение, я бы с удовольствием это услышал, но, пробовав дюжину разных подходов, он работал только для меня.

Недостаток: Мне нужно было установить тайм-аут в 500 мс (возможно, меньше было бы работать, но я хотел быть в безопасности), чтобы удостовериться, что я захватил окончательное значение x после того, как iOS совершила свой промах с помощью положение элемента. В результате, опыт очень рывком., но по крайней мере он работает

Решение

        var mobileInputReposition = function(){
             //if statement is optional, I wanted to restrict this script to mobile devices where the problem arose
            if(screen.width < 769){
                setTimeout(function(){
                    var parentFrame = $('#subscribe-popup-frame',window.parent.document);
                    var parentFramePosFull = parentFrame.position();
                    var parentFramePosFlip = parentFramePosFull['top'] * -1;
                    parentFrame.css({'position' : 'fixed', 'top' : parentFramePosFlip + 'px'});
                },500);
            }    
        }   

Затем просто вызовите mobileInputReposition в нечто вроде $('your-input-field).focus(function(){}) и $('your-input-field).blur(function(){})