iOS: Виртуальная клавиатура и пустота. Часть первая
В одном из моих рабочих проектов есть модуль чата. Ничего сверхъестественного, классический набор из двух компонентов:
- Список сообщений (куда ж без него)
- Поле ввода (чтобы было где разгуляться)
Список занимает всю доступную высоту и скроллится. Поле ввода всегда
зафиксировано внизу с помощью position: sticky;
Баг
Клиент обнаружил в этом модуле следующий баг:
- Тапнуть в поле ввода (сфокусироваться)
- Откроется виртуальная клавиатура iOS
- Проскроллить до конца страницы
Ожидание: дойдем до конца и либо упремся в него, как в стенку, либо словим «резиновый» эффект, который все так любят в iOS.
Результат: пустое пространство между клавиатурой и контентом:
Посмотреть пример (открывать, тапать и скроллить в Safari на iOS)
Данный баг возникает только в Safari и только при наличии открытой виртуальной клавиатуры.
Время костылей, господа!
Я потратил на анализ и исправление этого бага несколько рабочих дней и нашел аж два решения.
Первое — это просто шедевр инженерной мысли! Внимание: берем и просто сбрасываем фокус с поля, как только юзер начинает скроллить. Гениально же, а?
function resetFocus(): void {
const input = document.querySelector("input");
if (input) {
input.blur();
}
}
document.addEventListener("touchmove", () => resetFocus());
На самом деле, в какой-то момент я действительно думал, что этот ужасный костыль — единственный вариант, как, не дожидаясь фикса на стороне iOS, замаскировать проблему.
Спойлер: я ошибался, есть второе, хорошее решение, но оно требует определенной верстки и немного JS. Поэтому, чтобы не раздувать пост, я подробно расскажу об этом во второй части.
Но если совсем коротко: запрещаем скроллить body и переносим всю движуху внутрь дочернего элемента. Стили будут примерно такие:
html,
body {
position: fixed;
inset: 0 0 0 0;
overflow: hidden;
height: var(--window-inner-height);
touch-action: none;
}
После этого, кроме бага, пропадет эффект «растягивания» на странице.
Из интересного
В примере я специально сделал theme_color
и фон сайта разными,
чтобы баг прямо бросался в глаза. Если цвет будет одинаковый, проблема
будет не так заметна, но легче от этого никому не станет.
Занимательно, что этот баг оказался весьма распространенным явлением. После того как я перелопатил все свои стили, скрипты на проекте, мне пришла в голову идея проверить как обстоят дела с этим на других сайтах.
Из всех сайтов, на которых я проверял, только ВКонтакте справился на ура. Чего нельзя сказать про Ozon и Кинопоиск: