Как предотвратить прокрутку страницы, при открытом модальном окне
После скроллинга и закрытия модального окна пользователь попадает на совершенно другое место на странице. Потому что содержимое страницы перемещается вслед за скроллингом. Это можно предотвратить с помощью приемов CSS и JavaScript.
Начнем с чего-нибудь простого
Можно помешать перелистыванию станицы при открытом модальном окне, установив высоту модального окна на полную высоту области просмотра и используя overflow-y: hidden при открытом модальном диалоге:
body.modal-open {
height: 100vh;
overflow-y: hidden;
}
Но если перед открытием модального окна мы уже перешли к содержимому <body>, то получим небольшое горизонтальное смещение.
Чтобы избежать этого, зададим правый отступ элемента body.
body {
height: 100vh;
overflow-y: hidden;
padding-right: 15px; /* Avoid width reflow */
}
Чтобы все работало, модальное окно должно быть меньше, чем высота области просмотра. Иначе на странице появится полоса прокрутки.
Как на счет мобильной версии?
Данное решение отлично работает как на ПК, так и на Android. Но в браузере Safari для iOS не все так гладко. Потому что содержимое страницы все еще прокручивается при открытом модальном диалоге.
В качестве обходного пути можно установить элемент body в position: fixed:
body {
position: fixed;
}
Но осталась еще одна маленькая проблема. Предположим, что кнопка открытия modal находится внизу страницы и мы кликаем ее. Но из-за этого мы возвращаемся обратно в верхнюю часть экрана.
Необходимо обратиться к JavaScript
Мы можем использовать JavaScript, чтобы избежать проблемы с событием касания. Метод stopPropagation некорректно работает при обработке касания в устройствах на iOS. Но зато метод preventDefault действует отлично. Это означает, что нам необходимо добавить обработчик событий к каждому узлу DOM модального окна. Это можно реализовать с помощью jQuery.
Улучшим подход с фиксированным элементом body
Вот с чем мы работали:
body {
position: fixed;
}
Если мы знаем позицию верхней части прокрутки и используем ее в CSS, тогда элемент body не будет прокручиваться обратно к началу экрана. Для реализации можно применить JavaScript:
// Когда модальное окно открыто, фиксируем элемент body
document.body.style.position = 'fixed';
document.body.style.top = `-${window.scrollY}px`;
// Когда модальное окно скрыто, остаемся в верхней части позиции прокрутки
document.body.style.position = '';
document.body.style.top = '';
Но еще осталась одна проблема. На странице изменяется положение скроллинга при открытом диалоге и зафиксированном body. Поэтому нужно восстановить расположение ползунка прокрутки. Чтобы разобраться с проблемой, изменим код JavaScript.
// When the modal is hidden...
const top = document.body.style.top;
document.body.style.position = '';
document.body.style.top = '';
window.scrollTo(0, parseInt(scrollY || '0') * -1);
Теперь содержимое body больше не прокручивается при открытом модальном окне, а положение скроллинга сохраняется.