Как я могу предотвратить дикую прокрутку, когда поле формы ввода фиксированной позиции получает фокус?

У меня есть мобильное веб-приложение, которое отображает диалоговое окно в позиции: фиксированный элемент, накладывающий весь экран. Независимо от того, сколько контента отображается или насколько прокручивается страница, элемент оверлея уменьшает содержимое страницы, и диалог появляется поверх всего. В диалоговом окне есть поле <input type="search />.

На Android, когда пользователь вводит входное поле, чтобы придать ему фокус, происходит некоторое довольно неустойчивое поведение (но не всегда):

  • Появляется мягкая клавиатура, затем сразу исчезает.
  • Основная страница (покрытая наложением) прокручивает несколько десятков пикселей, иногда вверх, иногда вниз, иногда в обоих направлениях, а иногда и несколько раз. Это также происходит, когда поле ввода теряет фокус.
  • Элемент overlay мгновенно сдвигает несколько пикселей вниз и вправо, показывая основное содержимое вдоль верхнего и левого краев экрана. (Он возвращается к месту меньше, чем через секунду).

Это на Android 2.3.4 со встроенным браузером. Это может произойти и в других версиях Android.

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

<head>
  <style type="text/css">
    #menuoverlay {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 10;
    background-color: rgba(0,0,0,.75);
    text-align: center;
    }
    #menu {
    display: inline-block;
    margin-top: 1em;
    border: 3px solid #02b;
    border-radius: 8px;
    padding: 1ex;
    background-color: black;
    color: silver;
    }
  </style>
</head>

<body>
  <div id="menuoverlay">
    <div id="menu">
      ...menu items...
      ...menu items...
      <form action=""><input type="search"/></form>
    </div>
  </div>

  <div id="content">
    ...lots of stuff...
    ...lots of stuff...
    ...lots of stuff...
  </div>
<body>

Кто-нибудь еще видел это поведение? Вы нашли способ предотвратить это?


Очистка сети привела меня к нескольким сообщениям о подобных проблемах. Вот краткое изложение того, что я прочитал до сих пор:

  • На многих устройствах Android встроенный браузер, по-видимому, не использует поля ввода WebKit так, как ожидалось. Вместо этого, когда html-определенные поля получат фокус, браузер пытается покрыть их новыми текстовыми виджетами, которые он создает отдельно.
  • Эти повторяющиеся текстовые поля часто игнорируют стили CSS, создавая эффект, когда поля выглядят стилизованными до тех пор, пока они не получат фокус, а затем внезапно вернутся к стилю системы по умолчанию.
  • В браузере Android часто не удается правильно расположить эти повторяющиеся поля. Когда они неуместны, они иногда видны, но в других случаях только перемещают цели фокуса без каких-либо визуальных указаний, которые они переместили.
  • Эти проблемы часто возникают, когда элемент предка поля ввода имеет такие стили, как transform: translate3d(), -webkit-backface-visibility или position: fixed.

Вот некоторые релевантные ссылки:

Прокрутка текстового поля Android Browser по всему месту, непригодна для использования

Как стилизовать тег HTML INPUT, чтобы он поддерживал CSS, когда он сфокусировался на Android 2.2+?

Исходный браузер Android 2.2/2.3 и фиксированное позиционирование

Ответы

Ответ 1

Мне удалось предотвратить мгновенное смещение наложения, установив outline: none в мой элемент input.

Я получил прокручивающую и исчезающую клавиатуру прокрутки вниз, установив overflow: hidden в html body при показе диалога, а затем удалив его снова, скрывая диалог. У этого есть неприятный побочный эффект сброса позиции прокрутки страницы, поэтому я сохраняю его и восстанавливаю при необходимости, и обертываю все эти хакеры в условных выражениях, поэтому он работает только на Android. (Я надеюсь, что мои пользователи Android не будут слишком отвлекаться, когда они видят, что содержимое страницы изменяется под полупрозрачным наложением, когда диалог открыт.)

Интересно, что мне также удалось предотвратить прокрутку дикой страницы, перехватив событие touchstart на моем элементе overlay и вызвав функцию preventDefault(). Это заставляет меня задаться вопросом, было ли все это безумие вызвано последовательностью таких событий:

  • touchstart пузырьки до корня документа
  • браузер видит touchstart, где размещено дублирующее поле ввода
  • браузер фокусируется на поле ввода
  • мягкая клавиатура позволяет печатать в поле ввода
  • область просмотра изменена для размещения мягкой клавиатуры
  • измененный размер окна просмотра во время сенсорного события выглядит как перетаскивание касания в браузере.
  • ложное перетаскивание заставляет страницу прокручивать и отклонять клавиатуру.

Мне не удалось поймать touchstart, чтобы решить проблему, потому что это мешало полю ввода получать фокус, а вызов focus() из javascript просто не работал. Я прочитал, что браузер Android отключает метод focus() в полях ввода, что объясняет это поведение. Возможно, он делает это, потому что он не будет работать с дублирующимися текстовыми виджетами, создаваемыми над полями, определенными html.

Ответ 2

В моем случае "позиция: зафиксирована"; это не проблема, "vertical-align: center"; или "-webkit-box-align: center;" нажмите и закройте мягкую клавиатуру, чтобы использовать "-webkit-box-align: start;" решил мою проблему.