Просто отключите прокрутку, не скройте ее?

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

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

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

Ответ 1

Если страница под наложением может быть "исправлена" вверху, когда вы открываете оверлей, вы можете установить

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

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

  • Применить 'noscroll' к html, а не к телу, чтобы предотвратить двойные полосы прокрутки в IE
  • Чтобы проверить, есть ли на самом деле полоса прокрутки, перед добавлением класса noscroll. В противном случае сайт также переместится на новую полосу прокрутки без прокрутки.
  • Чтобы сохранить возможный scrollTop, чтобы вся страница не возвращалась в начало (например, обновление Fabrizio, но вам нужно получить значение перед добавлением класса noscroll)
  • Не все браузеры обрабатывают 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);

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

Ответ 3

С включенным 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();

Ответ 4

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

// 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);
});

Ответ 5

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

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

Ответ 6

Я ОП

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

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

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

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

Ответ 7

В качестве альтернативы вы можете скрыть панель прокрутки тела с помощью 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>

Ответ 8

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

Это немного волнует 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>

Ответ 9

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

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

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

Ответ 10

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

прежде чем показывать следы фактической позиции прокрутки:

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

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

Ответ 11

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

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

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

Живой тест.

Ответ 12

Мне нравится придерживаться метода "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 to body:

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

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

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

Стиль носкролла таков:

.noscroll { overflow: hidden; }

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

Ответ 13

<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>

Ответ 14

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

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

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

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

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

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

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

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

Ответ 15

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

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

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

Ответ 16

Вы можете сделать это с помощью 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.