При закрытии модального окна страница прокручивается вверх
Обновлено: 24.04.2024
После скроллинга и закрытия модального окна пользователь попадает на совершенно другое место на странице. Потому что содержимое страницы перемещается вслед за скроллингом.
Но это можно предотвратить с помощью приемов CSS и JavaScript.
Начнем с чего-нибудь простого
Можно помешать перелистыванию станицы при открытом модальном окне, установив высоту модального окна на полную высоту области просмотра и используя overflow-y: hidden при открытом модальном диалоге:
Но если перед открытием модального окна мы уже перешли к содержимому , то получим небольшое горизонтальное смещение.
Чтобы избежать этого, зададим правый отступ элемента body.
Чтобы все работало, модальное окно должно быть меньше, чем высота области просмотра. Иначе на странице появится полоса прокрутки.
Как на счет мобильной версии?
Данное решение отлично работает как на ПК, так и на Android. Но в браузере Safari для iOS не все так гладко. Потому что содержимое страницы все еще прокручивается при открытом модальном диалоге.
В качестве обходного пути можно установить элемент body в position: fixed:
Но осталась еще одна маленькая проблема. Предположим, что кнопка открытия modal находится внизу страницы и мы кликаем ее. Но из-за этого мы возвращаемся обратно в верхнюю часть экрана.
Необходимо обратиться к JavaScript
Мы можем использовать JavaScript, чтобы избежать проблемы с событием касания. Метод stopPropagation некорректно работает при обработке касания в устройствах на iOS. Но зато метод preventDefault действует отлично. Это означает, что нам необходимо добавить обработчик событий к каждому узлу DOM модального окна. Это можно реализовать с помощью jQuery.
Улучшим подход с фиксированным элементом body
Вот с чем мы работали:
Если мы знаем позицию верхней части прокрутки и используем ее в CSS, тогда элемент body не будет прокручиваться обратно к началу экрана. Для реализации можно применить JavaScript:
Но еще осталась одна проблема. На странице изменяется положение скроллинга при открытом диалоге и зафиксированном body. Поэтому нужно восстановить расположение ползунка прокрутки. Чтобы разобраться с проблемой, изменим код JavaScript.
Теперь содержимое body больше не прокручивается при открытом модальном окне, а положение скроллинга сохраняется.
Дайте знать, что вы думаете по этой теме материала в комментариях. За комментарии, лайки, дизлайки, отклики, подписки огромное вам спасибо!
Пожалуйста, опубликуйте ваши мнения по текущей теме статьи. За комментарии, подписки, дизлайки, отклики, лайки огромное вам спасибо!
Я пытался вызвать фрагмент javascript ниже при открытии модального окна, но безуспешно
Обратите внимание, что наш веб-сайт отказался от поддержки IE6, хотя IE7 + должен быть совместимым.
Bootstrap modal автоматически добавляет класс modal-open в тело, когда отображается модальный диалог, и удаляет его, когда диалог скрыт. Поэтому вы можете добавить в свой CSS следующее:
Вы можете утверждать, что приведенный выше код принадлежит базе кода CSS Bootstrap, но это простое решение, позволяющее добавить его на свой сайт.
Обновление от 8 февраля 2013 г.
Теперь это перестало работать в Twitter Bootstrap v. 2.3.0 - они больше не добавляют modal-open класс в тело.
Обходной путь - добавить класс в тело, когда модальное окно будет показано, и удалить его, когда модальное окно закрыто:
Обновление 11 марта 2013 г. Похоже, что modal-open класс вернется в Bootstrap 3.0 явно с целью предотвращения прокрутки:
Reintroduces .modal-open on the body (so we can nuke the scroll there)
@Bagata Cool - modal-open вернется в Bootstrap 3, поэтому при его запуске можно безопасно удалить приведенный выше код.
Вот почему нужно продолжать прокрутку вниз, если выбранный ответ вас не устраивает, есть вероятность, что вы найдете такие драгоценные камни. не ожидал, что ответ с более чем 97 голосами будет похоронен так глубоко под другими менее понравившимися комментариями.
проблема в том, что для предотвращения прокрутки документа вверх при открытии модального окна вам нужно было добавить body.modal-open
Принятый ответ не работает на мобильных устройствах (по крайней мере, iOS 7 с Safari 7), и я не хочу, чтобы MOAR JavaScript работал на моем сайте, когда будет работать CSS.
Этот CSS предотвратит прокрутку фоновой страницы под модальным окном:
Тем не менее, у него также есть небольшой побочный эффект, связанный с прокруткой вверх. position:absolute решает эту проблему, но вновь вводит возможность прокрутки на мобильном устройстве.
Я также добавляю это, чтобы нижележащая страница не прыгала влево / вправо при отображении / скрытии модальных окон.
Спасибо! Мобильные телефоны (по крайней мере, собственный браузер iOS и Android) вызывали у меня головную боль и не работали бы без них position: fixed .
Спасибо, что также включили код для предотвращения перехода страницы влево / вправо при отображении / скрытии модальных окон. Это было чрезвычайно полезно, и я убедился, что это решает проблему, с которой я столкнулся в Safari на iPhone 5c под управлением iOS 9.2.1.
Хотя я считаю, что это подойдет только для самых элементарных нужд, это было полезное исправление. Спасибо.
Вот как я сделал это, чтобы сохранить позицию прокрутки с помощью jquery: js const currPageScrollPos = $(window).scrollTop() $("body").removeClass("show_overlay") $(window).delay(5).scrollTop(currPageScrollPos)
Просто скройте переполнение тела, и оно не будет прокручиваться. Когда вы скрываете модальное окно, верните его к автоматическому.
Вы можете попробовать установить размер тела в соответствии с размером окна с помощью overflow: hidden, когда модальное окно открыто
при этом экран будет перемещаться каждый раз при открытии модального окна, что неудобно, мне просто нужно отключить фоновую прокрутку
не уверен, что вы можете использовать полосы прокрутки, связанные с браузером, и вы мало что можете с ними поделать
Дело не в том, чтобы остановить прокрутку модального окна, а в том, чтобы остановить прокрутку тела в фоновом режиме
это окно, которое прокручивается, если тело переполняет его. Например, полосы прокрутки не являются частью документа.
Вам нужно выйти за рамки ответа @ charlietfl и учитывать полосы прокрутки, иначе вы можете увидеть перекомпоновку документа.
Открытие модального окна:
- Запишите body ширину
- Установить body переполнение на hidden
Явно установите ширину тела, которая была на шаге 1.
Закрытие модального окна:
Установить body ширину на auto
Я получал "дергающийся" экран из-за отсутствия лучшего термина, и ключевым моментом здесь для меня было соблюдение настроек ширины. Благодаря тонну.
О боже, какая чудесная идея. @jpap, вы помогли мне решить проблему перекомпоновки документов, которая долго меня беспокоила.
Предупреждение: Опция ниже не имеет отношения к Bootstrap v3.0.x, поскольку прокрутка в этих версиях была явно ограничена самим модальным окном. Если вы отключите события колеса, вы можете случайно запретить некоторым пользователям просматривать контент в модальных окнах, высота которых превышает высоту области просмотра.
Еще один вариант: события колеса
Прокрутки событие не отменяемое. Однако можно отменить события колеса мыши и колеса мыши. Большое предостережение заключается в том, что не все устаревшие браузеры поддерживают их, Mozilla только недавно добавила поддержку последнего в Gecko 17.0. Я не знаю полного распространения, но IE6 + и Chrome их поддерживают.
Вот как их использовать:
JSFiddle
@AxeEffect теперь должен работать. Единственная проблема заключалась в том, что внешние ссылки на библиотеку Bootstrap изменились. Спасибо за внимание.
@TowerJimmy, вам, вероятно, нужно отменить события касания или перетаскивания для этого (если это вообще возможно)
Не удалось заставить его работать в Chrome, просто изменив CSS, потому что я не хотел, чтобы страница прокручивалась обратно вверх. Это сработало нормально:
Была проблема с переходом на вершину с сайдингом из угловатых материалов. Это был единственный ответ, который, похоже, работает во всех случаях (рабочий стол / мобильный + разрешить прокрутку в модальном / боковом меню + оставить фиксированное положение прокрутки тела без прыжков).
Попробуй это:
у меня это сработало. (поддерживает IE8)
Это работает, но также заставляет вас переходить наверх при открытии модального окна при использовании position: fixed .
Добавление класса is-modal-open или изменение стиля тега body с помощью javascript - это нормально, и он будет работать должным образом. Но проблема, с которой мы столкнемся, - это когда тело становится переполненным: скрытым, оно перескакивает наверх (scrollTop станет 0). Позже это станет проблемой для удобства использования.
В качестве решения этой проблемы вместо изменения тега body overflow: hidden измените его на теге html.
Это абсолютно правильный ответ, потому что общий консенсусный ответ прокручивает страницу вверх, что ужасно для пользователя. Вам следует написать об этом в блоге. В итоге я превратил это в глобальное решение.
По состоянию на ноябрь 2017 г. в Chrome появилось новое свойство css.
который решает эту проблему, хотя на момент написания имеет ограниченную кроссбраузерную поддержку.
см. ссылки ниже для получения полной информации и поддержки браузера
For Bootstrap, you might try this (working on Firefox , Chrome and Microsoft Edge ) :
Надеюсь это поможет.
Я не уверен насчет этого кода, но попробовать стоит.
Как я уже сказал, я не уверен на 100%, но все равно попробуйте.
@xorinzor вы указали в разделе комментариев ответа charlietfl, что это работает. Но вы сказали: это не предотвращает прокрутку тела при открытом модальном окне.
правда, но на данный момент это единственное решение, которое частично работает, и меня устраивает. Причина, по которой я пометил его ответ как ответ, состоит в том, что он раньше давал ответ.
@xorinzor правда, я думал, что ответил раньше него / нее, может быть какой-то странный глюк. это нормально, хотя
Ознакомьтесь с этим jsFiddle, чтобы увидеть, как он используется.
Это не так уж и давно, но у меня ничего из этого не работает, даже скрипка. Я все еще могу прокручивать окно, что мне не хватает?
@smhmic примерно через 20 раз открытия и закрытия ширина зеленого div становится равной open modal ширине кнопок. Chrome на 8
Чтобы страница не перескакивала вверх, а также предотвращала сдвиг содержимого вправо, добавьте класс к классу, body когда модальное окно запущено, и установите следующие правила CSS:
Это position:static и то, height:auto что объединяется, чтобы остановить скачок содержимого вправо. overflow-y:hidden; Останавливает страницу от того , прокручивать за модальным.
Многие предлагают "переполнение: скрыто" на теле, что не сработает (по крайней мере, в моем случае), поскольку заставит веб-сайт прокрутиться вверх.
Это решение, которое работает для меня (как на мобильных телефонах, так и на компьютерах) с использованием jQuery:
Это заставит прокрутку модального окна работать и предотвратит одновременную прокрутку веб-сайта.
Вы можете использовать следующую логику, я ее протестировал, и она работает (даже в IE)
следующий фрагмент (с использованием jquery) отключит прокрутку окна:
Теперь, когда вы удаляете модальное окно, не забудьте удалить класс noscroll в теге html:
Разве overflow нельзя установить на hidden ? +1 хотя, как это сработало для меня (используя hidden ).
В моей ситуации веб-страница изначально имеет полосу прокрутки. Всякий раз, когда я нажимаю модальное окно, полоса прокрутки не исчезает, а заголовок немного сдвигается вправо.
Затем я попытался добавить .modal-open (что рекомендовало большинство). Это действительно устранило проблемы: полоса прокрутки появляется после того, как я открываю модальное окно. Однако появляется еще один побочный эффект: «фон под заголовком немного сместится влево вместе с еще одной длинной полосой позади модального окна».
К счастью, после добавления все исправлено идеально. Фон заголовка и тела не сдвинулся, а в модальном окне все еще сохраняется полоса прокрутки.
Надеюсь, это поможет тем, кто все еще сталкивается с этой проблемой. Удачи!
Бывало у вас такое? Открываете модальное окно, прокручиваете, а после закрытия оказываетесь на странице в позиции, отличающейся от той, с которой его открывали.
Подобное может происходить из-за того, что модальные окна являются такими же элементами страницы, как и любые другие. Они могут располагаться в фиксированной позиции, не препятствуя работе с остальным содержимым документа.
Порой это не становится проблемой. Например, когда высота содержимого страницы не превышает высоту области видимости экрана пользователя. Однако, в остальных случаях мы неизбежно сталкиваемся с этим. Хорошей новостью является то, что мы можем предотвратить появление скролла с помощью трюка с использованием CSS и JavaScript.
При открытии модального окна можно просто устанавливать элемент body по высоте равным области видимости (viewport) и скрывать вертикальную прокрутку:
Решение имеет право на существование, но если перед открытием модального окна мы прокрутим элемент body , получим небольшую перерисовку содержимого. Ширина области видимости расширяется приблизительно на 15px, что соответствует ширине полосы прокрутки.
Давайте немного отрегулируем правый padding для body , чтобы избежать этого.
Обратите внимание – чтобы это сработало, модальное окно должно быть по высоте меньше области видимости. Иначе полоса прокрутки будет нужна.
Это решение отлично работает как на десктопах, так и на мобильных Android-устройствах. Однако, Safari для iOS требует немного больше внимания, поскольку body всё ещё может прокручиваться, когда модальное окно открыто.
Как альтернатива, мы можем задать для body фиксированное позиционирование.
Работает. Теперь body не будет реагировать на свайпы по экрану. Тем не менее, небольшая проблема всё же остаётся. Если кнопка, открывающая модальное окно, находится внизу страницы и чтобы её увидеть, нужно прокручивать страницу, при нажатии на эту кнопку и открытии модального окна, будет происходить автоматическая прокрутка страницы вверх, что может дезориентировать так же, как и фоновая прокрутка body , от которой мы пытаемся избавиться.
Можем использовать JavaScript, чтобы избежать всплытия события прикосновения к экрану. Все мы знаем, что при открытии модального окна, у него должен быть фоновый слой. К сожалению, в iOS метод stopPropagation() с событиями прикосновения работает немного неуклюже. Но у preventDefault() таких проблем нет. Это значит, что мы должны добавить обработчики событий к каждому DOM-элементу внутри модального окна, а не только к слою подложки или самому модальному окну. Хорошая новость в том, что много JavaScript-библиотек могут делать это, включая старый добрый jQuery.
Ах да, и ещё кое-что. Что если нам нужна прокрутка внутри модального окна? Нам всё ещё нужно вызвать реакцию на событие свайпа, но при достижении верха или низа модального окна, нам всё ещё нужно предотвращать всплытие. Кажется очень сложным (?? так что мы ещё не полностью выкарабкались).
Вот с чем мы работали:
С помощью JavaScript можно вычислить положение прокрутки страницы, и добавлять это значение в CSS. Благодаря этому body не будет прокручиваться обратно в начальную позицию.
Данное решение работает, но после закрытия окна всё ещё происходит небольшой сдвиг. А именно, похоже, когда модальное окно открыто и для body задано фиксированное позиционирование, страница уже теряет положение прокрутки. Следовательно, нам нужно восстановить положение. Давайте изменим JavaScript, чтобы учитывать этот момент.
Вот и всё. Теперь body не будет прокручиваться при открытом модальном окне, а положение прокрутки сохраняется и при открытии и при закрытии модального окна.
Вёрстка таких окон сначала кажется простой задачей. Модальные окна можно сделать даже без помощи JS только лишь с помощью CSS, но на практике они оказываются неудобными, и из-за маленьких недочетов модальные окна раздражают посетителей сайта.
В итоге было задумано сделать собственное простое решение.
Вообще говоря, есть несколько готовых скриптов, JavaScript библиотек, реализующих функционал модальных окон, например:
- Arctic Modal,
- jquery-modal,
- iziModal,
- Micromodal.js,
- tingle.js,
- Bootstrap Modal (из библиотеки Bootstrap) и др.
(в статье не рассматриваем решения на базе Frontend-фреймворков)
Несколькими из них я пользовался сам, но почти у всех находил какие-то недостатки. Некоторые из них требуют подключения библиотеки jQuery, которая есть не на всех проектах. Для разработки своего решения, нужно сначала определиться с требованиями.
Что мы ждём от модальных окон? Отвечая на этот вопрос, я основывался на докладе «Знакомьтесь, модальное окно» Анны Селезнёвой, а так-же на относительно старой статье NikoX «arcticModal — jQuery-плагин для модальных окон».
Итак, чтобы нам хотелось видеть?
Дисклеймер: Прежде чем мы рассмотрим подробности, сразу дам ссылку на готовый код получившейся библиотеки (HystModal) на GitHub, а также ссылку на демо+документацию.
Начнём с разметки.
1. Разметка HTML и CSS
1.1. Каркас модальных окон
Как открыть окно быстро? Самое простое решение: разместить всю разметку модального окна сразу в HTML странице. Затем скрывать/показывать это окно при помощи переключения классов CSS.
Набросаем такую разметку HTML (я назвал этот скрипт «hystmodal»):
Сделаем так, чтобы .hystmodal растягивался на всё окно браузера и закрывал собой содержимое страницы. Чтобы этого добиться, установим фиксированное позиционирование в CSS и приравняем свойства top, bottom, left и right к нулю.
В этом коде сделаны ещё две вещи:
- Так как мы хотим центрировать окно внутри страницы, превращаем .hystmodal в flex-контейнер с выравниваем его потомков по центру по вертикали и горизонтали.
- Окно может быть больше высоты экрана браузера, поэтому мы устанавливаем overflow-y: auto , чтобы при переполнении возникала полоса прокрутки. Также, для сенсорных экранов (в основном для Safari) нам стоит установить свойство -webkit-overflow-scrolling: touch , чтобы сенсорная прокрутка работала именно на этом блоке а не на странице.
Теперь установим стили для самого окна.
Кажется возникли сложности.
Проблема №1. Если высота окна больше высоты окна браузера, то контент окна будет обрезан сверху.
Это возникает из-за свойства justify-content: center . Оно позволяет нам удобно выровнять потомков по основной оси (по вертикали), но если потомок становится больше родителя то часть его становится недоступной даже при прокручиваемом контейнере. Подробнее можно посмотреть на stackoverflow. Решение – установить justify-content: flex-start , а потомку установить margin:auto . Это выровняет его по центру.
Проблема №2. В ie-11 если высота окна больше высоты окна браузера, то фон окна обрезается.
Решение: мы можем установить flex-shrink:0 потомку – тогда обрезки не происходит.
Проблема №3. В браузерах кроме Chrome нет отступа от нижней границы окна (т.е. padding-bottom не сработал).
Сложно сказать баг это браузеров или наоборот соответствует спецификации, но решения два:
- установить псевдоэлемент ::after после потомка и дать ему высоту вместо padding
- обернуть элемент в дополнительный блок и дать отступы уже ему.
Воспользуемся вторым методом. Добавим обертку .hystmodal__wrap . Так мы заодно обойдём и проблему №1, а вместо padding у родителя установим margin-top и margin-top у самого .hystmodal__window .
Наш итоговый html:
В код также добавлены некоторые aria и role атрибуты для обеспечения доступности.
Обновленный код CSS для обертки и окна.
1.2 Скрываем окно
Сейчас наше окно всегда видно. Когда говорят о скрытии элементов, первое что приходит на ум это переключать свойство display со значения none до нашего значения flex.
Но этот подход нас не устроит, ведь свойство display не анимируется. Все переходы дочерних элементов, указанные в свойстве transition, работать не будут.
Нам поможет другое свойство visibility:hidden . Оно скроет окно визуально, хотя и зарезервирует под него место. А так как все будущие окна на странице имеют фиксированное
позиционирование – они будут полностью скрыты и не повлияют на остальную страницу. Кроме того, на элементы с visibility:hidden нельзя установить фокус с клавиатуры, а от скрин-ридеров мы уже скрыли окна с помощью атрибута aria-hidden="true" .
Добавим также классы для открытого окна:
1.3 Оформление подложки
В лучшем случае, нам нужен отдельный html-элемент в качестве оверлея. Можно использовать и имеющийся элемент модального окна .hystmodal в качестве оверлея, но тогда анимация на этом элементе (например переход opacity) будет затрагивать и внутренние элементы. В итоге, не получится анимировать разные свойства для окна и оверлея отдельно.
Просто разместим элемент .hystmodal__shadow прямо перед закрывающим