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


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.