Проблема динамической высоты в мобильных браузерах
Динамические единицы измерения CSS (dvh, svh) были введены для решения проблемы отображения элементов при изменении размера видимой области экрана мобильного браузера. Однако они не учитывают появление виртуальной клавиатуры.
Когда открывается экранная клавиатура, элементы с позиционированием position: fixed оказываются перекрытыми. Это происходит потому, что спецификация CSS рассматривает клавиатуру как наложение поверх окна просмотра, а не как изменение его размеров. Таким образом, значения таких единиц, как dvh, остаются неизменными даже после появления клавиатуры.
Как определить высоту клавиатуры?
Для того чтобы корректно учитывать размер клавиатуры, можно использовать API визуального представления окна (Visual Viewport API). Высота клавиатуры вычисляется следующим образом:
const keyboardHeight = window.innerHeight - window.visualViewport.height;
При открытии клавиатуры значение visualViewport.height уменьшается, тогда как window.innerHeight остаётся фиксированным. Разница между этими значениями равна высоте клавиатуры.
Однако здесь есть нюанс: поведение отличается на разных платформах. Например, на iOS Safari при появлении клавиатуры окно прокручивается вверх, увеличивая значение visualViewport.offsetTop. При этом события изменения размера окна не вызываются. На Android Chrome же само окно просмотра сжимается, уменьшаясь в размере, вызывая событие изменения размера окна.
Решение проблемы
Чтобы учесть оба сценария, необходимо реализовать логику обработки событий таким образом, чтобы она работала одинаково на обеих платформах. Пример такой реализации выглядит так:
const handleWindowResize = () => {
const vv = window.visualViewport;
const currWidth = window.innerWidth;
const widthChanged = currWidth !== layoutWidthRef.current;
// Пропускаем обработку, если клавиатура открыта или ширина окна изменилась
if (!vv || (vv.offsetTop === 0 && widthChanged)) {
layoutHeightRef.current = window.innerHeight;
layoutWidthRef.current = currWidth;
}
};
Таким образом, мы можем автоматически обновлять размеры окна только при реальных изменениях ориентации устройства или размерах окна, избегая ложных срабатываний при открытии клавиатуры.