Как предотвратить прокрутку при открытии модального окна
Бред Ву написал на 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 можно будет забыть.
Курсы 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
Здравствуйте!
У меня вопрос в продолжение темы.
Данный код позволяет просто запретить прокрутку страницы при появлении модального окна. Но если модальное окно большое и выходит за рамки окна браузера, оно так же, естественно, не прокручивается.
Как сделать так, чтобы модальное окно прокручивалось, а страница, находящаяся на «нижнем слое» — нет, чтобы она оставалась на месте?
Так, к примеру, сделано на сайте Вконтакте. При просмотре, скажем, фотографии, можно прокручивать модальное окно просмотра фотографии, а основная страница при этом остаётся на месте.
Отключаем скролл (прокрутку) страницы при открытии модального окна
Все очень и очень просто! Обычно хватает использования body в стилях. Это скрывает полосу прокрутки страницы, а лежащий поверх слой с меню (или модальным окном) прокручиваем при помощи того же overflow: auto. Причем, специфические overflow-x и overflow-y лучше всего использовать только для отмены прокрутки по одной из осей, так как не все браузеры их вообще понимают.
Но и с самим overflow: hidden иногда бывают проблемы. Некоторые браузеры позволяют прокручивать такой блок (без полос прокрутки) скроллом мыши или касанием, а некоторые — нет.
Но это правильный способ и на чистом Джаваскрипт он выглядит так:
document. getElementsByTagName («body»)[0].style. overflow=»hidden»;
Но сегодня я работал над мобильным дизайном сайта jazzi-pool.ru и наткнулся на интересную особенность. 5 и 6 Айфон на браузере Сафари явно позволяют при быстром листании меню чуть оттягивать его в браузере вверх, цепляя пальцем контент страницы, что приводит к прокрутке сайта вверх. Хоть и под меню.
Это можно исправить, добавляя к body при открытии окна position: fixed; width: 100%;
document.getElementsByTagName («body»)[0].style. position=»fixed»;
document.getElementsByTagName («body»)[0].style. width=»100%»;
Контент и правда будет нельзя прокрутить. Но тут есть маленькая загвоздка. Когда мы уберем фиксированное позиционирование и закроем модальное окно, страница будет прокручена на самый верх, а не находиться в том месте, где мы его открывали. И если для работы модального окна это не имеет значения, то для меню — очень неудобно.
Но тут помог мой любимый JavaScript для определения высоты прокрутки документа:
function totop()
Я обычно физически создаю
и при вызове скрипта записываю в него высоту прокрутки документа document. getElementById(«totop»). innerHTML = totop(); а при закрытии модального окна — просто прокручиваю страницу к нужному месту при помощи scrollTo(0, document. getElementById(«totop»). innerHTML); Например, так и работает боковое меню на dikij.com.
Хотя, можно еще написать километровый скрипт для запрета события прокрутки колесиком мыши (window. onmousewheel), стрелками, пробелом и пальцем. но этим добром и так весь интернет забит. Проще найти готовый и переработать под свои нужды.
UPD. Можно еще добавить к BODY touch-action: none. Это поддерживают не все браузеры, но совместно с overflow: hidden должно сработать.
Как предотвратить прокрутку страницы, при открытом модальном окне
После скроллинга и закрытия модального окна пользователь попадает на совершенно другое место на странице. Потому что содержимое страницы перемещается вслед за скроллингом. Это можно предотвратить с помощью приемов CSS и JavaScript.
Начнем с чего-нибудь простого
Можно помешать перелистыванию станицы при открытом модальном окне, установив высоту модального окна на полную высоту области просмотра и используя overflow-y: hidden при открытом модальном диалоге:
body.modal-open
Но если перед открытием модального окна мы уже перешли к содержимому , то получим небольшое горизонтальное смещение.
Чтобы избежать этого, зададим правый отступ элемента body.
body < height: 100vh; overflow-y: hidden; padding-right: 15px; /* Avoid width reflow */ >
Чтобы все работало, модальное окно должно быть меньше, чем высота области просмотра. Иначе на странице появится полоса прокрутки.
Как на счет мобильной версии?
Данное решение отлично работает как на ПК, так и на Android. Но в браузере Safari для iOS не все так гладко. Потому что содержимое страницы все еще прокручивается при открытом модальном диалоге.
В качестве обходного пути можно установить элемент body в position: fixed:
body
Но осталась еще одна маленькая проблема. Предположим, что кнопка открытия modal находится внизу страницы и мы кликаем ее. Но из-за этого мы возвращаемся обратно в верхнюю часть экрана.
Необходимо обратиться к JavaScript
Мы можем использовать JavaScript, чтобы избежать проблемы с событием касания. Метод stopPropagation некорректно работает при обработке касания в устройствах на iOS. Но зато метод preventDefault действует отлично. Это означает, что нам необходимо добавить обработчик событий к каждому узлу DOM модального окна. Это можно реализовать с помощью jQuery.
Улучшим подход с фиксированным элементом body
Вот с чем мы работали:
body
Если мы знаем позицию верхней части прокрутки и используем ее в CSS, тогда элемент body не будет прокручиваться обратно к началу экрана. Для реализации можно применить JavaScript:
// Когда модальное окно открыто, фиксируем элемент body document.body.style.position = 'fixed'; document.body.style.top = `-$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 больше не прокручивается при открытом модальном окне, а положение скроллинга сохраняется.
