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

257

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

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

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

AND

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

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

37 ответов

392
Лучший ответ

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

body.modal-open {
    overflow: hidden;
}

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

Обновление 8 февраля 2013 года
Это теперь перестало работать в Twitter Boostrap 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
  • 2
    @ppetrid Я не ожидаю, что он вернется. Основываясь на этом написании: github.com/twitter/bootstrap/wiki/Upcoming-3.0-changes (смотрите внизу). Цитата: «Больше нет внутренней модальной прокрутки. Вместо этого модалы будут расти для размещения их контента, а страница прокручивается для размещения модальной моды».
Показать ещё 19 комментариев
85

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

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

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

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

Если вы знаете свой viewport (мой плагин для добавления области просмотра в <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 на корпусе.
  • 0
    Спасибо также за включение кода для предотвращения перехода страницы влево / вправо при показе / скрытии модальных окон. Это было чрезвычайно полезно, и я убедился, что это устраняет проблему, возникающую у меня в Safari на iPhone 5c под управлением iOS 9.2.1.
Показать ещё 2 комментария
24

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

Вот код:

$('#adminModal').modal().on('shown', function(){
    $('body').css('overflow', 'hidden');
}).on('hidden', function(){
    $('body').css('overflow', 'auto');
})
  • 3
    не работает на 2.3.2
  • 0
    Отлично! Это помогло мне. Благодарю.
19

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

  • 11
    это будет перемещать экран каждый раз, когда модал открывается, что не удобно, мне просто нужно отключить прокрутку фона
  • 0
    не уверен, что вы можете использовать полосы прокрутки, связанные с браузером, и вы не можете многое сделать с ними
Показать ещё 8 комментариев
16

Предупреждение:. Параметр ниже не относится к 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

  • 0
    Ваш JSFiddle не работает ни в Firefox 24, Chrome 24, ни в IE9.
  • 0
    @AxeEffect теперь должно работать. Единственная проблема заключалась в том, что внешние ссылки на библиотеку Bootstrap изменились. Спасибо за внимание.
Показать ещё 3 комментария
12

Вам нужно выйти за пределы @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

  • 0
    Я получал «нервный» экран из-за отсутствия лучшего термина, и ключом для меня было следование настройкам ширины. Благодаря тонну.
  • 1
    @Hcabnettek Yep: "jumpy" == "reflow документа". Рад, что это помогло вам! :-)
Показать ещё 3 комментария
8

Попробуйте следующее:

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

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

  • 2
    Это работает, но также заставляет вас прыгать наверх, когда вы открываете модальный режим при использовании position: fixed .
8
/* =============================
 * 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(); });
});
  • 1
    Это работает для сенсорных устройств?
6

Не удалось заставить его работать с 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.
  • 1
    Имел ли прыжок наверх проблему с угловатым материалом sidenavs. Это был единственный ответ, который, кажется, работает во всех случаях (рабочий стол / мобильный + разрешить прокрутку в модальном / sidenav + оставить фиксированное положение прокрутки тела без прыжков).
Показать ещё 1 комментарий
6

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

В jQuery:

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

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

  • 1
    Это не мешает телу прокручиваться при открытом модале
  • 0
    @xorinzor вы заявили в разделе комментариев ответа charlietfl, что это работает. Но вы сказали: это не мешает телу прокручиваться при открытом модале.
Показать ещё 2 комментария
4

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

В качестве решения этой проблемы вместо изменения тега body over: скрытое изменение на html-теге

$('#myModal').on('shown.bs.modal', function () {
  $('html').css('overflow','hidden');
}).on('hidden.bs.modal', function() {
  $('html').css('overflow','auto');
});
  • 1
    Это абсолютно правильный ответ, потому что общий консенсусный ответ прокручивает страницу вверх, что является ужасным опытом для пользователя. Вы должны написать блог об этом. Я закончил тем, что превратил это в глобальное решение.
  • 1
    Это сработало очень хорошо. (Y),
3

Лучшим решением является решение 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, чтобы увидеть его в использовании.

  • 0
    Это не так уж и старо, но ничего из этого не работает для меня, даже для скрипки. Я все еще могу прокручивать окно, что мне не хватает?
  • 0
    Откройте и закройте модальные несколько раз, и основной зеленый DIV сжимается и сжимается!
Показать ещё 3 комментария
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

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

Это решение, которое работает для меня (как на мобильных телефонах, так и на компьютерах), используя 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');
    });

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

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

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

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

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

Изображение 2345

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

Изображение 2346

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

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');
  • 0
    Разве overflow должно быть hidden ? +1, хотя, как это работает для меня (используя hidden ).
1

По состоянию на ноябрь 2017 года Chrome Введен новый объект css

overscroll-behavior: contain;

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

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

1

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

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

У меня была боковая панель, созданная с помощью checkbox hack. Но основная идея - сохранить документ 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);
            }
        });
    })

});
1

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

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

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

1

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

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

Я не уверен на 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; останавливает прокручивание страницы за модалом.

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

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

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

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

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
    Это также предотвращает прокрутку в модальном режиме.
  • 0
    Та же проблема. Вы нашли решение? @Daniel
Показать ещё 1 комментарий
0

Вышеприведенное происходит, когда вы используете модальный внутри другого модального. Когда я открываю модальный внутри другого модала, закрытие последнего удаляет класс modal-open из body. Исправление проблемы зависит от того, как вы закрываете последний модальный.

Если вы закрываете модальный код с помощью html,

<button type="button" class="btn" data-dismiss="modal">Close</button>

Затем вам нужно добавить слушателя, как это,

$(modalSelector).on("hidden.bs.modal", function (event) {
    event.stopPropagation();
    $("body").addClass("modal-open");
    return false;
});

Если вы закрываете модальный, используя javascript, например,

$(modalSelector).modal("hide");

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

setInterval(function(){$("body").addClass("modal-open");}, 300);
0

Небольшая заметка для тех, кто находится в SharePoint 2013. Тело уже имеет overflow: hidden. То, что вы ищете, это установить overflow: hidden в элементе div с id s4-workspace, например.

var body = document.getElementById('s4-workspace');
body.className = body.className+" modal-open";
0
   $('.modal').on('shown.bs.modal', function (e) {
      $('body').css('overflow-y', 'hidden');
   });
   $('.modal').on('hidden.bs.modal', function (e) {
      $('body').css('overflow-y', '');
   });
  • 0
    Пожалуйста, отредактируйте с дополнительной информацией. Ответы «только код» и «попробуй это» не приветствуются, поскольку они не содержат контента для поиска и не объясняют, почему кто-то должен «попробовать это». Мы прилагаем все усилия, чтобы быть источником знаний.
0

Вы должны добавить overflow: hidden в HTML для лучшей кросс-платформенной производительности.

Я бы использовал

html.no-scroll {
    overflow: hidden;
}
0

Я только что сделал это так...

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

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

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

прямо после него.

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

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

Попробуйте этот код:

$('.entry_details').dialog({
    width:800,
    height:500,
    draggable: true,
    title: entry.short_description,
    closeText: "Zamknij",
    open: function(){
        //    blokowanie scrolla dla body
        var body_scroll = $(window).scrollTop();
        $(window).on('scroll', function(){
            $(document).scrollTop(body_scroll);
        });
    },
    close: function(){
        $(window).off('scroll');
    }
}); 
0

Скрытие переполнения и фиксация позиции делает трюк, однако, с моей жидкостной конструкцией, он фиксирует ее за шириной браузера, поэтому ширина: 100% исправлена.

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

Я использую эту функцию vanilla js для добавления в тело класса "модально-открытый". (На основе smhmic ответа)

function freezeScroll(show, new_width)
{
    var innerWidth = window.innerWidth,
        clientWidth = document.documentElement.clientWidth,
        new_margin = ((show) ? (new_width + innerWidth - clientWidth) : new_width) + "px";

    document.body.style.marginRight = new_margin;
    document.body.className = (show) ? "modal-open" : "";
};
0

Это лучшее решение для меня:

Css:

.modal {
     overflow-y: auto !important;
}

И Js:

modalShown = function () {
    $('body').css('overflow', 'hidden');
},

modalHidden = function () {
    $('body').css('overflow', 'auto');
}
0

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

$(".modal").scroll(function() {
    console.log("scrolling!);
});
0

Это сработало для меня:

$("#mymodal").mouseenter(function(){
   $("body").css("overflow", "hidden"); 
}).mouseleave(function(){
   $("body").css("overflow", "visible");
});
-2

Эта проблема исправлена, Решение. Просто откройте свой bootstap.css и измените, как показано ниже.

body.modal-open,
.modal-open .navbar-fixed-top,
.modal-open .navbar-fixed-bottom {
  margin-right: 15px;
}

to

 body.modal-open,
.modal-open .navbar-fixed-top,
.modal-open .navbar-fixed-bottom {
  /*margin-right: 15px;*/
}

Пожалуйста, просмотрите приведенное ниже видео на YouTube менее 3 минут, и ваша проблема будет исправлена ​​... https://www.youtube.com/watch?v=kX7wPNMob_E

  • 0
    Кто-нибудь попробовал с этим ...?
  • 0
    Я думаю, что вы неправильно поняли весь вопрос. Речь идет не о расположении полосы прокрутки, а о предотвращении возможности прокрутки в фоновом режиме с помощью колесика мыши на компьютере или пальца на мобильных устройствах.
-6

HTML:

<body onscroll="stop_scroll()">

JavaScript:

function stop_scroll(){
    scroll(0,0) ;
}

Если вы установите флаг (bool) внутри stop_scroll(), вы можете решить, когда его задействовать (если вы хотите его только временно).

Это будет прокручиваться reset каждый раз, когда какой-либо элемент переполняет границы body, и окна имеют тенденцию прокручиваться (это абсолютно не зависит от полос прокрутки, overflow : hidden не имеет к этому отношения).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню