Как предотвратить прокрутку при открытии модального окна
Бред Ву написал на CSS Tricks статью про блокирование прокрутки основного контента при открытии модального окна — «Prevent Page Scrolling When a Modal is Open».
Прокрутка контента при открытом модальном окне ведёт к плохому пользовательскому опыту, так как после закрытия окна пользователь может оказаться в другом месте страницы. Бред рассматривает несколько вариантов решения этой проблемы. Пример с overflow-y: hidden очень простой, но не работает с мобильной версией iOS. Для блокирования скролла в iOS в статье описывается другой подход с использованием position: fixed и смещением, которое задаётся с помощью JavaScript.
В комментариях к статье пишут, что overflow: hidden для блокирования прокрутки документа работает в iOS 13. Мне стало интересно — нашёл тикет в трекере WebKit. Действительно, баг починили месяц назад. Остаётся подождать, когда большинство пользователей перейдёт на новую версию iOS, и о хаке с fixed можно будет забыть.
Запрет прокрутки при открытии модального окна

Одной из проблем реализации модальных окон является прокрутка контента под модальным окном. Как правило модальные окна находятся в фиксированной позиции, не препятствуя работе с остальным содержимым документа.
Как предотвратить прокрутку контента под модальным окном и сохранить позицию прокрутки над элементом на котором произошёл вызов модального окна, поможет Java-script код указанный ниже:
// Кода показывается модальное окно
// фиксируем боди и запоминаем позицию скролла
document.body.style.position = ‘fixed’;
document.body.style.top = `-$px`;
// Кода модальное окно скрывается
// убираем фиксацию боди и восстанавливаем позицию скролла
const scrollY = document.body.style.top;
document.body.style.position = »;
document.body.style.top = »;
window.scrollTo(0, parseInt(scrollY || ‘0’) * -1);
Теперь body не будет прокручиваться при открытом модальном окне, а положение прокрутки сохраняется и при открытии и при закрытии модального окна.
Категории
Тэги
Разработка сайтовБлогКонтакты
Запрет прокрутки при открытии модального окна

Бывало у вас такое? Открываете модальное окно, прокручиваете, а после закрытия оказываетесь на странице в позиции, отличающейся от той, с которой его открывали.
Подобное может происходить из-за того, что модальные окна являются такими же элементами страницы, как и любые другие. Они могут располагаться в фиксированной позиции, не препятствуя работе с остальным содержимым документа.
Порой это не становится проблемой. Например, когда высота содержимого страницы не превышает высоту области видимости экрана пользователя. Однако, в остальных случаях мы неизбежно сталкиваемся с этим. Хорошей новостью является то, что мы можем предотвратить появление скролла с помощью трюка с использованием CSS и JavaScript.
Давайте начнём с чего-нибудь простого
При открытии модального окна можно просто устанавливать элемент body по высоте равным области видимости (viewport) и скрывать вертикальную прокрутку:
body.modal-open
Решение имеет право на существование, но если перед открытием модального окна мы прокрутим элемент body , получим небольшую перерисовку содержимого. Ширина области видимости расширяется приблизительно на 15px, что соответствует ширине полосы прокрутки.
Давайте немного отрегулируем правый padding для body , чтобы избежать этого.
body < height: 100vh; overflow-y: hidden; padding-right: 15px; /* Avoid width reflow */ >
Обратите внимание – чтобы это сработало, модальное окно должно быть по высоте меньше области видимости. Иначе полоса прокрутки будет нужна.
Отлично. А что насчёт мобильных?
Это решение отлично работает как на десктопах, так и на мобильных Android-устройствах. Однако, Safari для iOS требует немного больше внимания, поскольку body всё ещё может прокручиваться, когда модальное окно открыто.
Как альтернатива, мы можем задать для body фиксированное позиционирование.
body
Работает. Теперь body не будет реагировать на свайпы по экрану. Тем не менее, небольшая проблема всё же остаётся. Если кнопка, открывающая модальное окно, находится внизу страницы и чтобы её увидеть, нужно прокручивать страницу, при нажатии на эту кнопку и открытии модального окна, будет происходить автоматическая прокрутка страницы вверх, что может дезориентировать так же, как и фоновая прокрутка body , от которой мы пытаемся избавиться.
Вот поэтому нам не обойтись без JavaScript
Можем использовать JavaScript, чтобы избежать всплытия события прикосновения к экрану. Все мы знаем, что при открытии модального окна, у него должен быть фоновый слой. К сожалению, в iOS метод stopPropagation() с событиями прикосновения работает немного неуклюже. Но у preventDefault() таких проблем нет. Это значит, что мы должны добавить обработчики событий к каждому DOM-элементу внутри модального окна, а не только к слою подложки или самому модальному окну. Хорошая новость в том, что много JavaScript-библиотек могут делать это, включая старый добрый jQuery.
Ах да, и ещё кое-что. Что если нам нужна прокрутка внутри модального окна? Нам всё ещё нужно вызвать реакцию на событие свайпа, но при достижении верха или низа модального окна, нам всё ещё нужно предотвращать всплытие. Кажется очень сложным (?? так что мы ещё не полностью выкарабкались).
Давайте улучшим фиксированный body
Вот с чем мы работали:
body
С помощью JavaScript можно вычислить положение прокрутки страницы, и добавлять это значение в CSS. Благодаря этому body не будет прокручиваться обратно в начальную позицию.
// When the modal is shown, we want a fixed body document.body.style.position = 'fixed'; document.body.style.top = `-$px`; // When the modal is hidden, we want to remain at the top of the scroll position document.body.style.position = ''; document.body.style.top = '';
Данное решение работает, но после закрытия окна всё ещё происходит небольшой сдвиг. А именно, похоже, когда модальное окно открыто и для body задано фиксированное позиционирование, страница уже теряет положение прокрутки. Следовательно, нам нужно восстановить положение. Давайте изменим JavaScript, чтобы учитывать этот момент.
// Когда модальное окно скрыто. const scrollY = document.body.style.top; document.body.style.position = ''; document.body.style.top = ''; window.scrollTo(0, parseInt(scrollY || '0') * -1);
Вот и всё. Теперь body не будет прокручиваться при открытом модальном окне, а положение прокрутки сохраняется и при открытии и при закрытии модального окна.
Курсы javascript
Собственно, есть модальное окно. Необходимо сделать его действительно модальным, т.е. запретить прокручивание подлежащего содержимого основного окна.
Устанавливала-снимала overflow: hidden для body. Функционально — то, что нужно, но при этом имеем неприятный побочный эффект в виде дерганья из-за изменения размеров экрана за счет скрытия/появления полосы прокрутки.
Можно ли решить этот вопрос без изменения значения св-ва overflow?
07.02.2013, 19:16
без статуса
Регистрация: 25.05.2012
Сообщений: 8,219
Последний раз редактировалось Deff, 07.02.2013 в 19:19 .
07.02.2013, 19:27
Интересующийся
Регистрация: 20.10.2010
Сообщений: 14
Огромное спасибо!
24.03.2014, 17:13
Новичок на форуме
Регистрация: 24.03.2014
Сообщений: 1
Здравствуйте!
У меня вопрос в продолжение темы.
Данный код позволяет просто запретить прокрутку страницы при появлении модального окна. Но если модальное окно большое и выходит за рамки окна браузера, оно так же, естественно, не прокручивается.
Как сделать так, чтобы модальное окно прокручивалось, а страница, находящаяся на «нижнем слое» — нет, чтобы она оставалась на месте?
Так, к примеру, сделано на сайте Вконтакте. При просмотре, скажем, фотографии, можно прокручивать модальное окно просмотра фотографии, а основная страница при этом остаётся на месте.