it-swarm.com.ru

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

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

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

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

166
Dejan.S

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

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

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

  1. Примените 'noscroll' к html вместо body, чтобы избежать двойных полос прокрутки в 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);

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

73
Mike Garcia

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

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

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

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

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

Я ОП

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

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

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

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

5
Dejan.S

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

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

3
mpen

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

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

2
0b10011

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

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

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

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

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

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

Тестовый пример в реальном времени .

0
Shadow Wizard

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

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

.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
Bhuvan Arora

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

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

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

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

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

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

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

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

Мне нравится придерживаться метода «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, вам также необходимо добавить отступы к этим элементам.

0
Janne Annala

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

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

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

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

0
malko