Предотвратить прокрутку тела при открытии модального


347

Я хочу, чтобы мое тело перестало прокручиваться при использовании колесика мыши, когда модал (с http://twitter.github.com/bootstrap ) на моем веб-сайте открыт.

Я попытался вызвать кусок JavaScript ниже, когда модал открывается, но безуспешно

$(window).scroll(function() { return false; });

И

$(window).live('scroll', function() { return false; });

Обратите внимание, что наш веб-сайт прекратил поддержку IE6, хотя IE7 + должен быть совместимым.

Ответы:


470

Bootstrap modalавтоматически добавляет класс modal-openк телу, когда отображается модальное диалоговое окно, и удаляет его, когда диалог скрыт. Поэтому вы можете добавить следующее в свой CSS:

body.modal-open {
    overflow: hidden;
}

Вы можете утверждать, что приведенный выше код принадлежит базе кода Bootstrap CSS, но это легко исправить, добавив его на свой сайт.

Обновление 8 февраля 2013 г.
Теперь это перестало работать в Twitter Bootstrap v. 2.3.0 - они больше не добавляют modal-openкласс в тело.

Обходной путь должен был бы добавить класс к телу, когда модал должен быть показан, и удалить его, когда модал закрыт:

$("#myModal").on("show", function () {
  $("body").addClass("modal-open");
}).on("hidden", function () {
  $("body").removeClass("modal-open")
});

Обновление 11 марта 2013 г. Похоже, modal-openкласс вернется в Bootstrap 3.0 явно для предотвращения прокрутки:

Повторно вводит .modal-open на теле (чтобы мы могли убрать свиток там)

Смотрите это: https://github.com/twitter/bootstrap/pull/6342 - посмотрите модальный раздел.


2
это больше не работает в начальной загрузке 2.2.2. Надеемся, что .modal-open вернется в будущем ... github.com/twitter/bootstrap/issues/5719
ppetrid

2
@ppetrid Я не ожидаю, что он вернется. Исходя из этого, пишите: github.com/twitter/bootstrap/wiki/Upcoming-3.0-changes (смотрите внизу). Цитата: «Больше нет внутренней модальной прокрутки. Вместо этого модалы будут расти для размещения своего контента, а прокрутка страницы - для размещения модальной».
MartinHN

2
@Bagata Cool - modal-openвернется в Bootstrap 3, поэтому при запуске следует безопасно удалить приведенный выше код.
MartinHN

2
Вот почему следует продолжать прокручивать вниз, если выбранный ответ не удовлетворяет вас, есть вероятность, что вы найдете такие драгоценные камни, как эти. не ожидал, что 97+ проголосовавших ответ похоронен так глубоко под другими менее любимыми комментариями.
Мохд Абдул Муджиб

2
проблема в том, что для предотвращения прокрутки документа вверх при открытии модального режима необходимо добавить body.modal-open {overflow: visible}. Ваше решение работает на данный момент, с той обратной стороной, что документ прокручивается вверх, как только открывается модальное окно
Патрик

120

Принятый ответ не работает на мобильных устройствах (iOS 7, по крайней мере, Safari 7), и я не хочу, чтобы на моем сайте запускался MOAR JavaScript, когда CSS подойдет.

Этот CSS предотвратит прокрутку фоновой страницы под модой:

body.modal-open {
    overflow: hidden;
    position: fixed;
}

Тем не менее, он также имеет небольшой побочный эффект по существу прокрутки к вершине. position:absoluteрешает эту проблему, но вновь вводит возможность прокрутки на мобильном телефоне.

Если вы знаете свой видовой экран ( мой плагин для добавления видового экрана к<body> ), вы можете просто добавить переключатель css для position.

body.modal-open {
    // block scroll for mobile;
    // causes underlying page to jump to top;
    // prevents scrolling on all screens
    overflow: hidden;
    position: fixed;
}
body.viewport-lg {
    // block scroll for desktop;
    // will not jump to top;
    // will not prevent scroll on mobile
    position: absolute; 
}

Я также добавляю это, чтобы предотвратить переход основной страницы влево / вправо при показе / скрытии модалов.

body {
    // STOP MOVING AROUND!
    overflow-x: hidden;
    overflow-y: scroll !important;
}

этот ответ - кс-пост.


7
Спасибо! Мобильные телефоны (по крайней мере, собственный браузер iOS и Android) доставляли мне головную боль и не работали бы без position: fixedтела.
Рауль Рене

Спасибо также за включение кода для предотвращения перехода страницы влево / вправо при показе / скрытии модальных объектов. Это было чрезвычайно полезно, и я убедился, что это устраняет проблему, возникающую в Safari на iPhone 5c под управлением iOS 9.2.1.
Элайджа Лофгрен

6
Чтобы исправить прокрутку наверх, вы можете записать положение перед добавлением класса, затем после удаления класса сделать window.scroll до записанной позиции. Вот как я это исправил для себя: pastebin.com/Vpsz07zd .
Инструмент

Хотя я чувствую, что это будет соответствовать только самым основным потребностям, это было полезным решением. Спасибо.
Стив Беннер

33

Просто скрыть переполнение тела, и это делает тело не прокручивать. Когда вы скрываете модал, верните его в автоматический режим.

Вот код:

$('#adminModal').modal().on('shown', function(){
    $('body').css('overflow', 'hidden');
}).on('hidden', function(){
    $('body').css('overflow', 'auto');
})

Превосходно! Это помогло мне. Спасибо.
pfcodes

21

Вы можете попробовать установить размер тела на размер окна с переполнением: скрыто, когда модальное окно открыто.


12
при этом каждый раз при открытии модального режима экран будет перемещаться, что не удобно, мне просто нужно отключить прокрутку фона
xorinzor

не уверен, что вы можете использовать полосы прокрутки, связанные с браузером, и вы не можете ничего с ними сделать
charlietfl

Вы можете установить модальное значение «исправлено», чтобы не двигаться при прокрутке
charlietfl


1
это окно прокручивается, если тело переполняет его. Например, полосы прокрутки не являются частью документа.
charlietfl

18

Вам нужно выйти за рамки ответа @ charlietfl и учетной записи для полос прокрутки, в противном случае вы можете увидеть перекомпоновку документа.

Открытие модального:

  1. Запишите bodyширину
  2. Установить bodyпереполнение наhidden
  3. Явно установите ширину тела, равную ширине шага 1.

    var $body = $(document.body);
    var oldWidth = $body.innerWidth();
    $body.css("overflow", "hidden");
    $body.width(oldWidth);

Закрытие модального:

  1. Установить bodyпереполнение наauto
  2. Установите bodyширинуauto

    var $body = $(document.body);
    $body.css("overflow", "auto");
    $body.width("auto");

Вдохновлено: http://jdsharp.us/jQuery/minute/calculate-scrollbar-width.php


Я получал «нервный» экран из-за отсутствия лучшего термина, и ключом для меня было следование настройкам ширины. Благодаря тонну.
Hcabnettek

1
@Hcabnettek Yep: "jumpy" == "reflow документа". Рад, что это помогло вам! :-)
Jpap

Есть ли решение CSS для этого? это работает во всех браузерах и мобильных устройствах?
Рубен

просто опечатка: это должно быть $body.css("overflow", "auto");на последнем этапе :)
schneikai

О, чувак, какая изумительная идея. @jpap, вы помогли мне решить проблему с перекомпоновкой документа, которая долго мучила меня.
Горан Радулович

17

Предупреждение: Опция ниже не относится к Bootstrap v3.0.x, поскольку прокрутка в этих версиях была явно ограничена самим модалом. Если вы отключите события колеса, вы можете непреднамеренно запретить некоторым пользователям просматривать контент в модальных моделях, высота которых превышает высоту области просмотра.


Еще один вариант: колесные события

Прокрутки событие не отменяемое. Однако можно отменить события колесика мыши и колеса . Большая оговорка в том, что не все устаревшие браузеры поддерживают их, Mozilla только недавно добавила поддержку последних в Gecko 17.0. Я не знаю полного распространения, но IE6 + и Chrome поддерживают их.

Вот как их использовать:

$('#myModal')
  .on('shown', function () {
    $('body').on('wheel.modal mousewheel.modal', function () {
      return false;
    });
  })
  .on('hidden', function () {
    $('body').off('wheel.modal mousewheel.modal');
  });

JSFiddle


Ваш JSFiddle не работает ни в Firefox 24, Chrome 24, ни в IE9.
AxeEffect

@AxeEffect теперь должно работать. Единственная проблема заключалась в том, что внешние ссылки на библиотеку Bootstrap изменились. Спасибо за внимание.
Merv

2
Это не мешает сенсорным устройствам прокручиваться, overflow:hiddenпока лучше.
Вебинан

5
все они работают, но не для мобильных устройств. -__- Протестировано Android 4.1 и Chrome
Tower Jimmy

@TowerJimmy вам, вероятно, нужно отменить события касания или перетаскивания для этого (если это вообще возможно)
xorinzor

9
/* =============================
 * Disable / Enable Page Scroll
 * when Bootstrap Modals are
 * shown / hidden
 * ============================= */

function preventDefault(e) {
  e = e || window.event;
  if (e.preventDefault)
      e.preventDefault();
  e.returnValue = false;  
}

function theMouseWheel(e) {
  preventDefault(e);
}

function disable_scroll() {
  if (window.addEventListener) {
      window.addEventListener('DOMMouseScroll', theMouseWheel, false);
  }
  window.onmousewheel = document.onmousewheel = theMouseWheel;
}

function enable_scroll() {
    if (window.removeEventListener) {
        window.removeEventListener('DOMMouseScroll', theMouseWheel, false);
    }
    window.onmousewheel = document.onmousewheel = null;  
}

$(function () {
  // disable page scrolling when modal is shown
  $(".modal").on('show', function () { disable_scroll(); });
  // enable page scrolling when modal is hidden
  $(".modal").on('hide', function () { enable_scroll(); });
});

9

Не удалось заставить его работать в Chrome, просто изменив CSS, потому что я не хотел, чтобы страница прокручивалась до самого верха. Это работало нормально:

$("#myModal").on("show.bs.modal", function () {
  var top = $("body").scrollTop(); $("body").css('position','fixed').css('overflow','hidden').css('top',-top).css('width','100%').css('height',top+5000);
}).on("hide.bs.modal", function () {
  var top = $("body").position().top; $("body").css('position','relative').css('overflow','auto').css('top',0).scrollTop(-top);
});

1
это единственное решение, которое работало для меня на начальной загрузке 3.2.
volx757

1
Имел ли прыжок наверх вопрос с угловатым материалом sidenavs. Это был единственный ответ, который, кажется, работает во всех случаях (рабочий стол / мобильный + разрешить прокрутку в модальном / sidenav + оставить фиксированное положение прокрутки тела без прыжков).
CYrixmorten

Это тоже единственное решение, которое действительно сработало для меня. TX
Deedz

9

Попробуй это:

.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
    height: 100%;
}

это сработало для меня. (поддерживает IE8)


4
Это работает, но также заставляет вас прыгать наверх при открытии модального режима при использовании position: fixed.
AlexioVay

8

Для Bootstrap вы можете попробовать это (работая над Firefox, Chromeи Microsoft Edge):

body.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
}

Надеюсь это поможет...


7

Добавление класса 'is-modal-open' или изменение стиля тега body с помощью javascript - это нормально, и все будет работать так, как должно. Но проблема, с которой мы столкнемся, заключается в том, что тело становится переполненным: скрытое, оно будет прыгать наверх (scrollTop станет 0). Это станет проблемой юзабилити позже.

Как решение этой проблемы, вместо того, чтобы менять переполнение тега body: hidden, измените его на html tag

$('#myModal').on('shown.bs.modal', function () {
  $('html').css('overflow','hidden');
}).on('hidden.bs.modal', function() {
  $('html').css('overflow','auto');
});

1
Это абсолютно правильный ответ, потому что общий консенсусный ответ прокручивает страницу вверх, что является ужасным опытом для пользователя. Вы должны написать блог об этом. Я закончил тем, что превратил это в глобальное решение.
Смит

6

Я не уверен насчет этого кода, но он того стоит.

В jQuery:

$(document).ready(function() {
    $(/* Put in your "onModalDisplay" here */)./* whatever */(function() {
        $("#Modal").css("overflow", "hidden");
    });
});

Как я уже говорил, я не уверен на 100%, но все равно попробую.


1
Это не мешает телу прокручиваться при открытом
модале

@xorinzor вы заявили в разделе комментариев ответа charlietfl, что это работает. Но вы сказали: это не мешает телу прокручиваться при открытом модале.
Аниш Гупта

правда, но пока это единственное решение, которое частично работает, и я в порядке. причина, по которой я отметил его ответ как ответ, состоит в том, что он был ранее с ответом.
xorinzor

@ xorinzor действительно, я думал, что отвечал перед ним / ней, может быть, какой-то странный сбой. все хорошо, хотя
Аниш Гупта

5

По состоянию на ноябрь 2017 года Chrome представил новую собственность CSS

overscroll-behavior: contain;

которая решает эту проблему, хотя на момент написания этой статьи ограничена кросс-браузерная поддержка.

см. ссылки ниже для получения полной информации и поддержки браузера


4

Лучшее решение - это решение css-only, body{overflow:hidden}используемое большинством из этих ответов. Некоторые ответы содержат исправление, которое также предотвращает «скачок», вызванный исчезающей полосой прокрутки; однако, ни один не был слишком изящен. Итак, я написал эти две функции, и они, кажется, работают довольно хорошо.

var $body = $(window.document.body);

function bodyFreezeScroll() {
    var bodyWidth = $body.innerWidth();
    $body.css('overflow', 'hidden');
    $body.css('marginRight', ($body.css('marginRight') ? '+=' : '') + ($body.innerWidth() - bodyWidth))
}

function bodyUnfreezeScroll() {
    var bodyWidth = $body.innerWidth();
    $body.css('marginRight', '-=' + (bodyWidth - $body.innerWidth()))
    $body.css('overflow', 'auto');
}

Проверьте этот jsFiddle, чтобы увидеть его в использовании.


Это не так уж и старо, но ничего из этого не работает для меня, даже для скрипки. Я все еще могу прокручивать окно, что мне не хватает?
приземлился

Откройте и закройте модальное несколько раз, и основной зеленый DIV сжимается и сжимается!
Вебинан

@Webinan Я не вижу этого в Chrome на Win7. Какой у вас размер браузера и области просмотра?
Стивен М. Харрис

1
@smhmic примерно после 20 раз открытия и закрытия ширина зеленого div становится равной open modalширине кнопок. Chrome 8
Webinan

Аналогично ответу @ jpap ( stackoverflow.com/a/16451821/5516499 ), но с добавленными ошибками. :-(
Киви Шапиро

4

Многие предлагают «переполнение: скрытый» на теле, которое не будет работать (по крайней мере, в моем случае), так как это заставит сайт прокручиваться вверх.

Это решение, которое работает для меня (как на мобильных телефонах, так и на компьютерах), используя jQuery:

    $('.yourModalDiv').bind('mouseenter touchstart', function(e) {
        var current = $(window).scrollTop();
        $(window).scroll(function(event) {
            $(window).scrollTop(current);
        });
    });
    $('.yourModalDiv').bind('mouseleave touchend', function(e) {
        $(window).off('scroll');
    });

Это заставит работать модальную прокрутку и предотвратит одновременную прокрутку сайта.


Похоже, что это решение также исправляет эту ошибку iOS: hackernoon.com/…
Gotenks

3

Вы можете использовать следующую логику, я протестировал ее, и она работает (даже в IE)

   <html>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">

var currentScroll=0;
function lockscroll(){
    $(window).scrollTop(currentScroll);
}


$(function(){

        $('#locker').click(function(){
            currentScroll=$(window).scrollTop();
            $(window).bind('scroll',lockscroll);

        })  


        $('#unlocker').click(function(){
            currentScroll=$(window).scrollTop();
            $(window).unbind('scroll');

        })
})

</script>

<div>

<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<button id="locker">lock</button>
<button id="unlocker">unlock</button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

</div>

2

Я не уверен на 100%, что это будет работать с Bootstrap, но стоит попробовать - он работал с Remodal.js, который можно найти на github: http://vodkabears.github.io/remodal/, и это будет иметь смысл для методов быть очень похожим.

Чтобы остановить переход страницы наверх, а также предотвратить смещение содержимого по правому краю, добавьте класс, bodyкогда запускается модал, и установите следующие правила CSS:

body.with-modal {
    position: static;
    height: auto;
    overflow-y: hidden;
}

Это position:staticи то, height:autoчто объединяет, чтобы остановить скачок контента вправо. overflow-y:hidden;Останавливает страницу от того , прокручивать за модальным.


Это решение отлично работает для меня в Safari 11.1.1, Chrome 67.0.3396.99 и Firefox 60.0.2. Спасибо!
Дом

2

На основании этой скрипки: http://jsfiddle.net/dh834zgw/1/

следующий фрагмент (с использованием jquery) отключит прокрутку окна:

 var curScrollTop = $(window).scrollTop();
 $('html').toggleClass('noscroll').css('top', '-' + curScrollTop + 'px');

И в вашем css:

html.noscroll{
    position: fixed;
    width: 100%;
    top:0;
    left: 0;
    height: 100%;
    overflow-y: scroll !important;
    z-index: 10;
 }

Теперь, когда вы удаляете модал, не забудьте удалить класс noscroll в теге html:

$('html').toggleClass('noscroll');

Не должно overflowбыть установлено hidden? +1 хотя как это у меня сработало (использую hidden).
mhulse

2

У меня была боковая панель, которая была сгенерирована путем взлома флажков. Но основная идея - сохранить документ scrollTop и не изменять его при прокрутке окна.

Мне просто не понравилось, что страница прыгает, когда тело становится «переполненным: скрытым».

window.addEventListener('load', function() {
    let prevScrollTop = 0;
    let isSidebarVisible = false;

    document.getElementById('f-overlay-chkbx').addEventListener('change', (event) => {
        
        prevScrollTop = window.pageYOffset || document.documentElement.scrollTop;
        isSidebarVisible = event.target.checked;

        window.addEventListener('scroll', (event) => {
            if (isSidebarVisible) {
                window.scrollTo(0, prevScrollTop);
            }
        });
    })

});


2

К сожалению, ни один из ответов выше не устранил мои проблемы.

В моей ситуации веб-страница изначально имеет полосу прокрутки. Всякий раз, когда я нажимаю на модал, полоса прокрутки не исчезает, а заголовок немного смещается вправо.

Затем я попытался добавить .modal-open{overflow:auto;}(что большинство людей рекомендовало). Это действительно исправило проблемы: полоса прокрутки появляется после того, как я открываю модальное окно. Тем не менее, появляется еще один побочный эффект, который заключается в том, что «фон под заголовком немного сместится влево вместе с еще одним длинным баром позади модального»

Длинный бар позади модального

К счастью, после того, как я добавил {padding-right: 0 !important;}, все исправлено отлично. И заголовок, и фон тела не двигались, а модал все еще сохраняет полосу прокрутки.

Фиксированное изображение

Надеюсь, что это может помочь тем, кто все еще застрял в этой проблеме. Удачи!


1

Большинство частей здесь, но я не вижу ответа, который бы все это соединил.

Проблема тройная.

(1) предотвратить прокрутку базовой страницы

$('body').css('overflow', 'hidden')

(2) и удалите полосу прокрутки

var handler = function (e) { e.preventDefault() }
$('.modal').bind('mousewheel touchmove', handler)

(3) очистить, когда модал уволен

$('.modal').unbind('mousewheel touchmove', handler)
$('body').css('overflow', '')

Если модальный режим не полноэкранный, примените привязки .modal к полноэкранному наложению.


4
Это также предотвращает прокрутку в модальном режиме.
Даниэль

Та же проблема. Вы нашли решение? @Daniel
AlexioVay

@ Вей Вроде. Проверьте это: blog.christoffer.me/…
Даниэль

1

Мое решение для Bootstrap 3:

.modal {
  overflow-y: hidden;
}
body.modal-open {
  margin-right: 0;
}

потому что для меня единственный overflow: hiddenв body.modal-openклассе не помешал смещению страницы влево из-за оригинала margin-right: 15px.


1

Я просто сделал это так ...

$('body').css('overflow', 'hidden');

Но когда исчез скроллер, он переместил все правильно на 20 пикселей, поэтому я добавил

$('body').css('margin-right', '20px');

сразу после этого.

Работает для меня.


Это работает, только если модальный размер меньше размера экрана.
Сергей

1

Если модальное значение - 100% высота / ширина, «мышиный указатель / уход» будет работать, чтобы легко включить / отключить прокрутку. Это действительно сработало для меня:

var currentScroll=0;
function lockscroll(){
    $(window).scrollTop(currentScroll);
} 
$("#myModal").mouseenter(function(){
    currentScroll=$(window).scrollTop();
    $(window).bind('scroll',lockscroll); 
}).mouseleave(function(){
    currentScroll=$(window).scrollTop();
    $(window).unbind('scroll',lockscroll); 
});

1

работал на меня

$('#myModal').on({'mousewheel': function(e) 
    {
    if (e.target.id == 'el') return;
    e.preventDefault();
    e.stopPropagation();
   }
});

1

Почему бы не сделать это, как Булма? Когда модальный активен, тогда добавьте в html их класс .is-clipped, который переполнен: hidden! Важный; И это все.

Редактировать: Окей, Булма имеет эту ошибку, поэтому вы должны добавить также другие вещи, как

html.is-modal-active {
  overflow: hidden !important;
  position: fixed;
  width: 100%; 
}

1

Поскольку для меня эта проблема представлена ​​в основном на iOS, я предоставляю код, который можно исправить только на iOS:

  if(!!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)) {
    var $modalRep    = $('#modal-id'),
        startScrollY = null, 
        moveDiv;  

    $modalRep.on('touchmove', function(ev) {
      ev.preventDefault();
      moveDiv = startScrollY - ev.touches[0].clientY;
      startScrollY = ev.touches[0].clientY;
      var el = $(ev.target).parents('#div-that-scrolls');
      // #div-that-scrolls is a child of #modal-id
      el.scrollTop(el.scrollTop() + moveDiv);
    });

    $modalRep.on('touchstart', function(ev) {
      startScrollY = ev.touches[0].clientY;
    });
  }

1

Ни один из приведенных выше ответов не работал идеально для меня. Поэтому я нашел другой способ, который хорошо работает.

Просто добавьте scroll.(namespace)слушателя и установите scrollTopсамый documentпоследний из его значений ...

а также удалите слушателя в вашем близком сценарии.

// in case of bootstrap modal example:
$('#myModal').on('shown.bs.modal', function () {
  
  var documentScrollTop = $(document).scrollTop();
  $(document).on('scroll.noScroll', function() {
     $(document).scrollTop(documentScrollTop);
     return false;
  });

}).on('hidden.bs.modal', function() {

  $(document).off('scroll.noScroll');

});

Обновить

Кажется, это плохо работает на Chrome. Любое предложение, чтобы исправить это?



0

Для тех, кто интересуется, как получить событие прокрутки для модала начальной загрузки 3:

$(".modal").scroll(function() {
    console.log("scrolling!);
});
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.