Просто отключить прокрутку, а не скрыть это?


200

Я пытаюсь отключить полосу прокрутки html / body родительского элемента при использовании лайтбокса. Главное слово здесь - отключить . Я не хочу скрывать это с overflow: hidden;.

Причиной этого является то, overflow: hiddenчто сайт прыгает и занимает область, где была прокрутка.

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


1
Возможна ли прокрутка? (Есть ли в лайтбоксе полосы прокрутки?)
Šime Vidas

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

В чем проблема с использованием лайтбокса с полосой прокрутки?
Мэнни

1
@Dejan Потому что я знаю, как отключить всю прокрутку - это отключило бы основную полосу прокрутки, но также и в лайтбоксе ...
Шиме Видас

1
Пожалуйста, не редактируйте ответ обратно в этот пост. Раздел ответов ниже для ответов. Если у вас есть ответ на ваш вопрос, который отличается от ответа ниже, вы можете добавить свое собственное решение в выбор ответа.
Создатель

Ответы:


174

Если страница под оверлеем может быть «зафиксирована» вверху, при открытии оверлея вы можете установить

body { position: fixed; overflow-y:scroll }

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

body { position: static; overflow-y:auto }

Я просто предложил этот способ только потому, что вам не нужно менять какое-либо событие прокрутки

Обновить

Вы также можете сделать небольшое улучшение: если вы получите document.documentElement.scrollTopсвойство через javascript непосредственно перед открытием слоя, вы можете динамически назначить это значение как topсвойство элемента body: при таком подходе страница будет стоять на своем месте, независимо от того, ' на вершине или если вы уже прокрутили.

Css

.noscroll { position: fixed; overflow-y:scroll }

JS

$('body').css('top', -(document.documentElement.scrollTop) + 'px')
         .addClass('noscroll');

2
это портит мой макет, но с некоторыми изменениями это может просто сработать.
Мне

4
с небольшой модификацией это работает. я добавил ширину: 100%; я ушел обновить мой вопрос с решением, но вы можете изменить ваш с шириной: 100% ;? спасибо за предложение
Dejan.S

3
Я не знаю почему, но это работает лучше для меня: $('body').css('top', -($('body').scrollTop()) + 'px').addClass('noscroll');
PDXIII

4
@ whitesiroi, ты прав. Я обновил скрипку: jsfiddle.net/evpozdniakov/2m8km9wg Спасибо!
Евпоздняков

1
Для тех, кто читает комментарии к решению, последняя скрипка предоставляет решение для отключения и повторного включения полосы прокрутки, сохраняя при этом положение полосы прокрутки в обоих случаях. Спасибо!
user1063287 31.01.16

80

Четыре небольших дополнения к выбранному решению:

  1. Примените noscroll к html, а не к телу, чтобы избежать двойных полос прокрутки в IE
  2. Чтобы проверить, есть ли на самом деле полоса прокрутки, перед добавлением класса 'noscroll'. В противном случае сайт также будет перепрыгивать при нажатии новой полосы прокрутки без прокрутки.
  3. Чтобы сохранить любой возможный scrollTop, чтобы вся страница не возвращалась наверх (как обновление Фабрицио, но вам нужно получить значение перед добавлением класса 'noscroll')
  4. Не все браузеры обрабатывают scrollTop так же, как описано на http://help.dottoro.com/ljnvjiow.php

Полное решение, которое работает для большинства браузеров:

CSS

html.noscroll {
    position: fixed; 
    overflow-y: scroll;
    width: 100%;
}

Отключить прокрутку

if ($(document).height() > $(window).height()) {
     var scrollTop = ($('html').scrollTop()) ? $('html').scrollTop() : $('body').scrollTop(); // Works for Chrome, Firefox, IE...
     $('html').addClass('noscroll').css('top',-scrollTop);         
}

Включить прокрутку

var scrollTop = parseInt($('html').css('top'));
$('html').removeClass('noscroll');
$('html,body').scrollTop(-scrollTop);

Спасибо Фабрицио и Деяну за то, что они поставили меня на правильный путь, и Бродинго за решение с двойной полосой прокрутки.


1
Это хорошо зарекомендовало себя на рабочем столе, но на iPhone он создал пустой белый экран, пока читатель не попытался прокрутить страницу. Когда читатель попытался взаимодействовать со страницей, предполагаемый экран стал видимым с заблокированной прокруткой.
Михаил Халили

Это работало отлично с FancyBox на IPad , чтобы отключить прокрутки лайтбокс изображения с afterLoad()и afterCloseобратных вызовов. Может быть полезно для других, ищущих этот вопрос.
Томанов

В части «enable scroll» вы можете удалить атрибут style, помещенный в элемент html после вызова «disable scroll»; не так ли?
Бен

3
JQuery стандартизирует собственные DOM, scrollTopтак что строка 2 кода «Отключить прокрутку» может быть выражена как $( window ).scrollTop().
Барни

Я думаю, что к этому нужно добавить еще одну вещь. В Chrome в OSX браузер может «перебирать», придавая скроллингу ощущение упругости. С этим кодом, если вы находитесь в серой области над или под страницей и наводите курсор на то место, где вы отключаете прокрутку. Это будет придерживаться точки выше / ниже окна браузера. По этой причине вам нужно добавить проверку на отрицательную величину прокрутки: if (scrollTop < 0) { scrollTop = 0; }. Вот полный код для отключения gist.github.com/jayd3e/2eefbbc571cd1668544b .
JayD3e

34

С включенным jQuery:


отключить

$.fn.disableScroll = function() {
    window.oldScrollPos = $(window).scrollTop();

    $(window).on('scroll.scrolldisabler',function ( event ) {
       $(window).scrollTop( window.oldScrollPos );
       event.preventDefault();
    });
};

включить

$.fn.enableScroll = function() {
    $(window).off('scroll.scrolldisabler');
};

использование

//disable
$("#selector").disableScroll();
//enable
$("#selector").enableScroll();

1
это было идеально для меня, предыдущий ответ заставил мою страницу отскочить, этот не делает
Богдан Томи

рад, что я мог помочь, вам, возможно, понадобится проверить и «touchmove», для мобильных устройств, ура
ceed

Ну, это почти сработало для меня. Он чудесно работал на Windows (Firefox, Chrome) и MacOS в Firefox ... но затем я перешел к Windows IE и Edge, вместе с MacOS в Chrome и Safari. Проблема больше не была в том, что страница перепрыгивала из стороны в сторону, но полоса прокрутки перепрыгивала сверху вниз в текущую позицию или страница мерцала вверх. Человек, это было так , так близко. Может быть, мы все еще можем заставить его работать.
Стивен Вентимилья

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

13

Я ОП

С помощью ответа от fcalderan я смог сформировать решение. Я оставляю свое решение здесь, поскольку оно дает ясность в том, как его использовать, и добавляет очень важную деталь,width: 100%;

Я добавляю этот класс

body.noscroll
{
    position: fixed; 
    overflow-y: scroll;
    width: 100%;
}

это сработало для меня, и я использовал Fancyapp.


11

Это сработало очень хорошо для меня ....

// disable scrolling
$('body').bind('mousewheel touchmove', lockScroll);

// enable scrolling
$('body').unbind('mousewheel touchmove', lockScroll);


// lock window scrolling
function lockScroll(e) {
    e.preventDefault();
}

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

например

$('button').on('click', function() {
     $('body').bind('mousewheel touchmove', lockScroll);
});

Это лучший ответ из всех них
Jafo

7

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

$('body').on('mousewheel touchmove', function(e) {
      e.preventDefault();
});

4

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

let marginRightPx = 0;
if(window.getComputedStyle) {
    let bodyStyle = window.getComputedStyle(document.body);
    if(bodyStyle) {
        marginRightPx = parseInt(bodyStyle.marginRight, 10);
    }
}

let scrollbarWidthPx = window.innerWidth - document.body.clientWidth;
Object.assign(document.body.style, {
    overflow: 'hidden',
    marginRight: `${marginRightPx + scrollbarWidthPx}px`
});

А затем вы можете добавить отключенную полосу прокрутки на страницу, чтобы заполнить пробел:

textarea {
  overflow-y: scroll;
  overflow-x: hidden;
  width: 11px;
  outline: none;
  resize: none;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  border: 0;
}
<textarea></textarea>

Я сделал именно это для моей собственной реализации лайтбокса. Кажется, до сих пор работает хорошо.


1
Мне действительно нравится этот метод больше всего. Очень просто и прекрасно работает. Спасибо!
dericcain

2

Это решение, с которым мы пошли. Просто сохраните позицию прокрутки при открытии оверлея, прокрутите назад до сохраненной позиции каждый раз, когда пользователь попытался прокрутить страницу, и отключите прослушиватель, когда оверлей закрыт.

Это немного нервно в IE, но работает как шарм в Firefox / Chrome.

var body = $("body"),
  overlay = $("#overlay"),
  overlayShown = false,
  overlayScrollListener = null,
  overlaySavedScrollTop = 0,
  overlaySavedScrollLeft = 0;

function showOverlay() {
  overlayShown = true;

  // Show overlay
  overlay.addClass("overlay-shown");

  // Save scroll position
  overlaySavedScrollTop = body.scrollTop();
  overlaySavedScrollLeft = body.scrollLeft();

  // Listen for scroll event
  overlayScrollListener = body.scroll(function() {
    // Scroll back to saved position
    body.scrollTop(overlaySavedScrollTop);
    body.scrollLeft(overlaySavedScrollLeft);
  });
}

function hideOverlay() {
  overlayShown = false;

  // Hide overlay
  overlay.removeClass("overlay-shown");

  // Turn scroll listener off
  if (overlayScrollListener) {
    overlayScrollListener.off();
    overlayScrollListener = null;
  }
}

// Click toggles overlay
$(window).click(function() {
  if (!overlayShown) {
    showOverlay();
  } else {
    hideOverlay();
  }
});
/* Required */
html, body { margin: 0; padding: 0; height: 100%; background: #fff; }
html { overflow: hidden; }
body { overflow-y: scroll; }

/* Just for looks */
.spacer { height: 300%; background: orange; background: linear-gradient(#ff0, #f0f); }
.overlay { position: fixed; top: 20px; bottom: 20px; left: 20px; right: 20px; z-index: -1; background: #fff; box-shadow: 0 0 5px rgba(0, 0, 0, .3); overflow: auto; }
.overlay .spacer { background: linear-gradient(#88f, #0ff); }
.overlay-shown { z-index: 1; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<h1>Top of page</h1>
<p>Click to toggle overlay. (This is only scrollable when overlay is <em>not</em> open.)</p>
<div class="spacer"></div>
<h1>Bottom of page</h1>
<div id="overlay" class="overlay">
  <h1>Top of overlay</h1>
  <p>Click to toggle overlay. (Containing page is no longer scrollable, but this is.)</p>
  <div class="spacer"></div>
  <h1>Bottom of overlay</h1>
</div>


Действительно работает, но портит дизайн в случае фиксированного заголовка, так как полоса прокрутки ныряет под него.
Леон

@LeonWillens Я не уверен, что ты имеешь в виду. Если вы обеспокоены накладкой появляющейся под фиксированным заголовком, вам нужно настроить z-indexна .overlay-shownбыть больше , чем фиксированный заголовок. (У меня есть этот код, запущенный в производство на сайте с фиксированным заголовком, и он отлично работает.)
0b10011

Нет, я говорил о полосе прокрутки bodyтега. Я экспериментировал с вашим кодом вчера, и у меня есть фиксированный заголовок в верхней части моей страницы. Если я обработаю прокрутку с помощью bodyтега, полоса прокрутки будет находиться под фиксированным заголовком.
Леон

1
@LeonWillens Ой, похоже, что я исправил это в какой-то момент и забыл обновить это. Похоже, вместо этого $("body")мы используем $(window). И вместо z-index: -1наложения, чтобы скрыть его, вы можете использовать visibility: hiddenили подобное. См. Jsfiddle.net/8p2gfeha для быстрого теста, чтобы увидеть, работает ли он. Фиксированный заголовок больше не отображается в верхней части полосы прокрутки. В конце концов я постараюсь включить эти изменения в ответ.
0b10011

Работает как шарм! Спасибо :)
Леон

1

У меня была похожая проблема: левое меню, которое, когда оно появляется, предотвращает прокрутку. Как только высота была установлена ​​на 100vh, полоса прокрутки исчезла, и содержимое дернулось вправо.

Поэтому, если вы не против оставить полосу прокрутки включенной (но установить окно на полную высоту, чтобы оно нигде не прокручивалось), тогда другой возможностью является установка крошечного нижнего поля, при котором полосы прокрутки будут отображаться:

body {
    height: 100vh;
    overflow: hidden;
    margin: 0 0 1px;
}

Не overflow:hiddenмешает ли маржа иметь какой-либо эффект?
Koja

0

Вы можете сохранить переполнение: скрытое, но управлять позицией прокрутки вручную:

перед показом следите за фактическим положением прокрутки:

var scroll = [$(document).scrollTop(),$(document).scrollLeft()];
//show your lightbox and then reapply scroll position
$(document).scrollTop(scroll[0]).scrollLeft(scroll[1]);

он должен работать


0

Грубым, но рабочим способом будет принудительная прокрутка вверх, таким образом, эффективно отключая прокрутку:

var _stopScroll = false;
window.onload = function(event) {
    document.onscroll = function(ev) {
        if (_stopScroll) {
            document.body.scrollTop = "0px";
        }
    }
};

Когда вы открываете лайтбокс, поднимите флаг и, закрыв его, опустите флаг.

Живой тестовый кейс .


0

Мне нравится придерживаться метода "overflow: hidden" и просто добавить padding-right, который равен ширине полосы прокрутки.

Получить функцию ширины полосы прокрутки, по lostsource .

function getScrollbarWidth() {
    var outer = document.createElement("div");
    outer.style.visibility = "hidden";
    outer.style.width = "100px";
    outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps

    document.body.appendChild(outer);

    var widthNoScroll = outer.offsetWidth;
    // force scrollbars
    outer.style.overflow = "scroll";

    // add innerdiv
    var inner = document.createElement("div");
    inner.style.width = "100%";
    outer.appendChild(inner);        

    var widthWithScroll = inner.offsetWidth;

    // remove divs
    outer.parentNode.removeChild(outer);

    return widthNoScroll - widthWithScroll;
}

При отображении наложения добавьте класс «noscroll» в html и добавьте padding-right для body:

$(html).addClass("noscroll");
$(body).css("paddingRight", getScrollbarWidth() + "px");

При сокрытии удалите класс и отступы:

$(html).removeClass("noscroll");
$(body).css("paddingRight", 0);

Стиль Noscroll таков:

.noscroll { overflow: hidden; }

Обратите внимание, что если у вас есть какие-либо элементы с position: fixed, вам также необходимо добавить отступы к этим элементам.


Я использовал это решение. Это помогло мне избежать двойных полос прокрутки (одна «пустая» для тела и вторая для содержимого наложения). Это также очень хорошо работает на OSX, который может показывать или не показывать полосы прокрутки вообще.
Novazembla

0

<div id="lightbox">находится внутри <body>элемента, поэтому при прокрутке лайтбокса вы также прокручиваете тело. Решение состоит в том, чтобы не расширять <body>элемент более чем на 100%, размещать длинное содержимое внутри другого divэлемента и добавлять полосу прокрутки, если необходимо, к этому divэлементу с помощью overflow: auto.

html {
  height: 100%
}
body {
  margin: 0;
  height: 100%
}
#content {
  height: 100%;
  overflow: auto;
}
#lightbox {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
<html>
  <body>
    <div id="content">much content</div>
    <div id="lightbox">lightbox<div>
  </body>
</html>

Теперь прокрутка над лайтбоксом (и над ним body) не имеет никакого эффекта, потому что тело не превышает 100% высоты экрана.


0

Все системы на основе javascript для модальных / лайтбоксов используют переполнение при отображении модальных / лайтбоксов, тегов html или body.

Когда лайтбокс отображается, js вызывает переполнение, скрытое в теге html или body. Когда лайтбокс скрыт, некоторые удаляют скрытый, другие нажимают на авто переполнение в тегах html или body.

Разработчики, работающие на Mac, не видят проблемы с полосой прокрутки.

Просто замените скрытое на unset, чтобы контент не проскальзывал под модальностью удаления полосы прокрутки.

Лайтбокс открыть / показать:

<html style="overflow: unset;"></html>

Лайтбокс закрыть / скрыть:

<html style="overflow: auto;"></html>

0

Если страница под оверлеем может быть «зафиксирована» вверху, при открытии оверлея вы можете установить

.disableScroll { position: fixed; overflow-y:scroll }

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

Чтобы сохранить положение страницы, сделайте это в jquery

$('body').css('top', - ($(window).scrollTop()) + 'px').addClass('disableScroll');

Когда вы закрываете оверлей, просто возвращаете эти свойства

var top = $('body').position().top;
$('body').removeClass('disableScroll').css('top', 0).scrollTop(Math.abs(top));

Я просто предложил этот способ только потому, что вам не нужно менять какое-либо событие прокрутки


0

Это остановит отображение окна просмотра на вершину, сохранив положение прокрутки и восстановив его при включении прокрутки.

CSS

.no-scroll{
  position: fixed; 
  width:100%;
  min-height:100vh;
  top:0;
  left:0;
  overflow-y:scroll!important;
}

JS

var scrollTopPostion = 0;

function scroll_pause(){
  scrollTopPostion = $(window).scrollTop();
  $("body").addClass("no-scroll").css({"top":-1*scrollTopPostion+"px"});
}

function scroll_resume(){
  $("body").removeClass("no-scroll").removeAttr("style");
  $(window).scrollTop(scrollTopPostion);
}

Теперь все, что вам нужно сделать, это вызвать функции

$(document).on("click","#DISABLEelementID",function(){
   scroll_pause();
});

$(document).on("click","#ENABLEelementID",function(){
   scroll_resume();
});

0

Другое решение, позволяющее избавиться от скачка содержимого на фиксированном модальном уровне при удалении прокрутки тела, состоит в нормализации ширины страницы:

body {width: 100vw; overflow-x: hidden;}

Затем вы можете играть с фиксированной позицией или переполнением: скрыто за телом, когда модал открыт. Но это скроет горизонтальные полосы прокрутки - обычно они не нужны на адаптивном веб-сайте.


-1

Вы можете сделать это с помощью Javascript:

// Classic JS
window.onscroll = function(ev) {
  ev.preventDefault();
}

// jQuery
$(window).scroll(function(ev) {
  ev.preventDefault();
}

А затем отключите его, когда ваш лайтбокс закрыт.

Но если ваш лайтбокс содержит полосу прокрутки, вы не сможете прокручивать ее, пока она открыта. Это потому что windowсодержит как bodyи #lightbox. Поэтому вы должны использовать архитектуру, подобную следующей:

<body>
  <div id="global"></div>
  <div id="lightbox"></div>
</body>

А затем применить onscrollсобытие только на #global.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.