Забороняйте прокручування BODY, коли відкривається модальний режим


347

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

Я намагався зателефонувати фрагменту javascript нижче, коли модал відкритий, але без успіху

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

І

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

Зауважте, наш веб-сайт відмовився від підтримки IE6, хоча IE7 + має бути сумісним.

Відповіді:


469

Bootstrap's 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/isissue/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: видимо}. Ваше рішення працює на даний момент, з недоліком того, що документ прокручується доверху, коли модал відкриється
Патрік

120

Прийнята відповідь не працює на мобільному пристрої (принаймні iOS 7 w / 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;
}

ця відповідь є x-post.


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

8
не про припинення модального прокрутки, а про зупинку тіла на задньому плані від прокрутки
xorinzor

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" == "поповнення документа". Рада, що вам це допомогло! :-)
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
Був стрибок до верхнього питання з кутово-матеріальними сиденами. Це була єдина відповідь, яка, здається, працює у всіх випадках (настільний / мобільний + дозволяють прокручувати модальний / сиденав + залишити положення прокрутки тіла фіксованим без стрибків).
cYrixmorten

Це також єдине рішення, яке насправді працювало на мене. tx
Dezz

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). Це стане проблемою зручності використання згодом.

Як рішення цієї проблеми, замість того, щоб змінити переповнення тегів тіла: приховано змінити його на html-тег

$('#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, що 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 разів відкриття та закриття ширини зеленого дива стає рівним open modalширині кнопок. Chrome on 8
Вебінан

Подібний відповідь @ 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

@Vay Сортування. Перевірте це: 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, який переповнюється: приховано! Важливо; І це все.

Редагувати: Окей, у Bulma є ця помилка, тому вам потрібно додати також інші речі, наприклад

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');

});

оновлення

Здається, це не дуже добре працює з хромом. будь-яка пропозиція виправити це?



0

Для тих, хто цікавиться, як отримати подію прокрутки для модального завантаження 3:

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