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

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

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

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

14 ответов


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

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

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

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

спасибо Фабрицио и Деян поставив меня на правильный путь и Brodingo для решение двойной полосы прокрутки


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

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

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

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

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

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

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


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

это немного нервный на 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>

Я ОП

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

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

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

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


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

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

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

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

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

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

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


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

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

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

текущий тестовый случай.


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

получить функцию ширины полосы прокрутки, по 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 и добавьте заполнение-справа от тела:

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

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

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

стиль noscroll таков:

.noscroll { overflow: hidden; }

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


<div id="lightbox"> внутри <body> элемент, таким образом, при прокрутке lightbox вы также прокручиваете тело. Решение не продлевать <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% экрана высота.


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