Запретить прокрутку тела, но разрешить прокрутку наложения



Я искал решение типа "лайтбокс", которое позволяет это, но еще не нашел его (пожалуйста, предложите, если вы знаете о нем).



поведение, которое я пытаюсь воссоздать, похоже на то, что вы увидите в Pinterest при нажатии на изображение. Наложение прокручивается (как и в целом наложение перемещается вверх, как страница на странице) но тело за оверлея исправлена.



Я попытался создать это с помощью только CSS (т. е. a div оверлея поверх всей страницы и тела с overflow: hidden), но это не мешает div с прокруткой.



как сохранить тело / страницу от прокрутки, но продолжать прокрутку внутри полноэкранного контейнера?

2178   17  

17 ответов:

теория

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

наложение (созданное на лету или уже внутри страницы и сделанное видимым через display: block, это не имеет никакого значения) имеет position : fixed и overflow-y: scroll С top,left,right и bottom свойства, установленные в 0: этот стиль делает наложение заполнить весь видовой экран.

The div внутри оверлея вместо этого просто в position: static тогда вертикальная полоса прокрутки, которую вы видите, связана с этим элементом. В результате содержимое прокручивается, но наложение остается фиксированным.

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

в качестве последнего шага вы должны также удалить noscroll класс body (таким образом, свойство overflow возвращает свое начальное значение)


код

Пример Codepen

(он работает, изменяя aria-hidden атрибут наложения, чтобы показать и скрыть его и увеличить его доступность).

разметки
(открытое кнопка)

<button type="button" class="open-overlay">OPEN LAYER</button>

(кнопка наложения и закрытия)

<section class="overlay" aria-hidden="true">
  <div>
    <h2>Hello, I'm the overlayer</h2>
    ...   
    <button type="button" class="close-overlay">CLOSE LAYER</button>
  </div>
</section>

CSS

.noscroll { 
  overflow: hidden;
}

.overlay { 
   position: fixed; 
   overflow-y: scroll;
   top: 0; right: 0; bottom: 0; left: 0; }

[aria-hidden="true"]  { display: none; }
[aria-hidden="false"] { display: block; }

Javascript(vanilla-JS)

var body = document.body,
    overlay = document.querySelector('.overlay'),
    overlayBtts = document.querySelectorAll('button[class$="overlay"]');

[].forEach.call(overlayBtts, function(btt) {

  btt.addEventListener('click', function() { 

     /* Detect the button class name */
     var overlayOpen = this.className === 'open-overlay';

     /* Toggle the aria-hidden state on the overlay and the 
        no-scroll class on the body */
     overlay.setAttribute('aria-hidden', !overlayOpen);
     body.classList.toggle('noscroll', overlayOpen);

     /* On some mobile browser when the overlay was previously
        opened and scrolled, if you open it again it doesn't 
        reset its scrollTop property */
     overlay.scrollTop = 0;

  }, false);

});

наконец, вот еще один пример, в котором оверлей открывается с эффектом затухания с помощью CSS transition применил к opacity собственность. Также padding-right применяется, чтобы избежать оплавления на основной текст, когда полоса прокрутки исчезает.

пример Codepen (fade)

CSS

.noscroll { overflow: hidden; }

@media (min-device-width: 1025px) {
    /* not strictly necessary, just an experiment for 
       this specific example and couldn't be necessary 
       at all on some browser */
    .noscroll { 
        padding-right: 15px;
    }
}

.overlay { 
     position: fixed; 
     overflow-y: scroll;
     top: 0; left: 0; right: 0; bottom: 0;
}

[aria-hidden="true"] {    
    transition: opacity 1s, z-index 0s 1s;
    width: 100vw;
    z-index: -1; 
    opacity: 0;  
}

[aria-hidden="false"] {  
    transition: opacity 1s;
    width: 100%;
    z-index: 1;  
    opacity: 1; 
}

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

body.noscroll{
    position:fixed;
    overflow:hidden;
}

Не используйте overflow: hidden; on body. Он автоматически прокручивает все вверх. Там нет необходимости в JavaScript либо. Используйте overflow: auto;. Это решение даже работает с мобильным Safari:

структура HTML

<div class="overlay">
    <div class="overlay-content"></div>
</div>

<div class="background-content">
    lengthy content here
</div>

стилизация

.overlay{
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    background-color: rgba(0, 0, 0, 0.8);

    .overlay-content {
        height: 100%;
        overflow: scroll;
    }
}

.background-content{
    height: 100%;
    overflow: auto;
}

посмотреть демо здесь исходный код здесь.

обновление:

для людей, которые хотят клавиатуры пробел, страница вверх / вниз, чтобы работать: вам нужно чтобы сосредоточиться на наложении, например, нажав на него, или вручную JS фокусируясь на нем перед этой частью div будет реагировать на клавиатуру. То же самое, когда наложение "выключено", так как оно просто перемещает наложение в сторону. В противном случае для браузера, это просто два нормальных divs и он не знал бы, почему он должен сосредоточиться на любом из них.

стоит отметить, что иногда добавление "overflow: hidden" к тегу body не выполняет эту работу. В этих случаях вам также придется добавить свойство в HTML-тег.

html, body {
    overflow: hidden;
}

у большинства решений есть проблема, что они не сохраняют положение прокрутки, поэтому я посмотрел, как это делает Facebook. В дополнение к установке содержимого подложки в position: fixed они также устанавливают верхнюю динамически, чтобы сохранить положение прокрутки:

scrollPosition = window.pageYOffset;
mainEl.style.top = -scrollPosition + 'px';

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

window.scrollTo(0, scrollPosition);

Я создал небольшой пример, чтобы продемонстрировать это решение

let overlayShown = false;
let scrollPosition = 0;

document.querySelector('.toggle').addEventListener('click', function() {
  if (overlayShown) {
		showOverlay();
  } else {
    removeOverlay();
  }
  overlayShown = !overlayShown;
});

function showOverlay() {
    scrollPosition = window.pageYOffset;
  	const mainEl = document.querySelector('.main-content');
    mainEl.style.top = -scrollPosition + 'px';
  	document.body.classList.add('show-overlay');
}

function removeOverlay() {
		document.body.classList.remove('show-overlay');
  	window.scrollTo(0, scrollPosition);
    const mainEl = document.querySelector('.main-content');
    mainEl.style.top = 0;
}
.main-content {
  background-image: repeating-linear-gradient( lime, blue 103px);
  width: 100%;
  height: 200vh;
}

.show-overlay .main-content {
  position: fixed;
  left: 0;
  right: 0;
  overflow-y: scroll; /* render disabled scroll bar to keep the same width */
}

.overlay {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.3);
  overflow: auto;
}

.show-overlay .overlay {
  display: block;
}

.overlay-content {
  margin: 50px;
  background-image: repeating-linear-gradient( grey, grey 20px, black 20px, black 40px);
  height: 120vh;
}

.toggle {
  position: fixed;
  top: 5px;
  left: 15px;
  padding: 10px;
  background: red;
}
  <main class="main-content"></main>

  <div class="overlay">
    <div class="overlay-content"></div>
  </div>
  
  <button class="toggle">Overlay</button>

overscroll-behavior свойство css позволяет переопределить поведение прокрутки переполнения браузера по умолчанию при достижении верхней / нижней части содержимого.

просто добавьте следующие стили наложения:

.overlay {
   overscroll-behavior: contain;
   ...
}

сайт CodePen демо

в настоящее время работает в Chrome, Firefox и IE(caniuse)

подробности Google developers article.

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

<div id="content">
</div>
<div id="overlay">
</div>

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

выбранный ответ правильный, но имеет некоторые ограничения:

  • супер жесткий "бросает" с пальцем будет по-прежнему прокручивать <body> на фоне
  • Открытие виртуальной клавиатуры, нажав <input> в модальном будет направлять все будущие свитки в <body>

у меня нет исправления для первого вопроса, но я хотел бы пролить свет на второй. К сожалению, загрузочный использовал, чтобы иметь эту проблему клавиатуры документированы, но они утверждали, что это было исправлено, цитируя http://output.jsbin.com/cacido/quiet в качестве примера исправления.

действительно, этот пример отлично работает на iOS с моими тестами. Однако обновление его до последней версии Bootstrap (v4) нарушает его.

в попытке выяснить, в чем разница между ними, я уменьшил тестовый случай, чтобы больше не зависеть от Bootstrap,http://codepen.io/WestonThayer/pen/bgZxBG.

решающие факторы причудливы. Во избежание проблема с клавиатурой, похоже, требует этого background-colorне установить на корень <div> содержащие модальные и содержимое модала должно быть вложено в другой <div>, который может иметь background-color set.

чтобы проверить его, раскомментируйте нижеприведенную строку в Примере Codepen:

.modal {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  display: none;
  overflow: hidden;
  -webkit-overflow-scrolling: touch;
  /* UNCOMMENT TO BREAK */
/*   background-color: white; */
}

для сенсорных устройств, попробуйте добавить 1px широкий,101vh мин-высота прозрачный div в обертке наложения. Затем добавьте -webkit-overflow-scrolling:touch; overflow-y: auto; в обертке. Это обманывает мобильное сафари, думая, что наложение прокручивается, тем самым перехватывая событие касания от тела.

вот пример страницы. Открыть на мобильном safari: http://www.originalfunction.com/overlay.html

https://gist.github.com/YarGnawh/90e0647f21b5fa78d2f678909673507f

Я нашел этот вопрос, пытаясь решить проблему, которую я имел с моей страницей на Ipad и Iphone - тело прокручивалось, когда я отображал фиксированный div как всплывающее окно с изображением.

некоторые ответы хороши, однако ни один из них не решил мою проблему. Я нашел следующее сообщение в блоге Кристофер Петтерссон. Решение, представленное там, помогло решить проблему, которую я имел с устройствами iOS, и это помогло моей проблеме прокрутки фона.

шесть вещей, которые я узнал о резинке iOS Safari прокрутка

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

"для того, чтобы отключить, что пользователь может прокручивать фоновую страницу в то время как" меню открыто", можно контролировать, какие элементы должны быть разрешены для прокрутки или нет, применяя некоторые JavaScript и класс CSS.

на основе этого Stackoverflow ответ вы можете контролировать, что элементы с отключением прокрутки не должны выполните их действие прокрутки по умолчанию при запуске события touchmove."

 document.ontouchmove = function ( event ) {

    var isTouchMoveAllowed = true, target = event.target;

    while ( target !== null ) {
        if ( target.classList && target.classList.contains( 'disable-scrolling' ) ) {
            isTouchMoveAllowed = false;
            break;
        }
        target = target.parentNode;
    }

    if ( !isTouchMoveAllowed ) {
        event.preventDefault();
    }
};

а затем поместите класс disable-scrolling на страницу div:

<div class="page disable-scrolling">

Я хотел бы добавить к предыдущим ответам, потому что я пытался это сделать, и некоторые макеты сломались, как только я переключил тело в положение:исправлено. Чтобы этого избежать, мне пришлось также установить высоту тела на 100%:

function onMouseOverOverlay(over){
    document.getElementsByTagName("body")[0].style.overflowY = (over?"hidden":"scroll");
    document.getElementsByTagName("html")[0].style.position = (over?"fixed":"static");
    document.getElementsByTagName("html")[0].style.height = (over?"100%":"auto");
}

используйте следующий HTML:

<body>
  <div class="page">Page content here</div>
  <div class="overlay"></div>
</body>

затем JavaScript для перехвата и остановки скроллинга:

$(".page").on("touchmove", function(event) {
  event.preventDefault()
});

затем, чтобы вернуть все в норму:

$(".page").off("touchmove");

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

overscroll-behavior: contain;

на вашем наложении в CSS.

если цель состоит в том, чтобы отключить на мобильных / сенсорных устройствах, то самый простой способ сделать это с помощью touch-action: none;.

пример:

const app = document.getElementById('app');
const overlay = document.getElementById('overlay');

let body = '';

for (let index = 0; index < 500; index++) {
  body += index + '<br />';
}

app.innerHTML = body;
app.scrollTop = 200;

overlay.innerHTML = body;
* {
  margin: 0;
  padding: 0;
}

html,
body {
  height: 100%;
}

#app {
  background: #f00;
  position: absolute;
  height: 100%;
  width: 100%;
  overflow-y: scroll;
  line-height: 20px;
}

#overlay {
  background: rgba(0,0,0,.5);
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 100%;
  padding: 0 0 0 100px;
  overflow: scroll;
}
<div id='app'></div>
<div id='overlay'></div>

(пример не работает в контексте переполнения стека. Вам нужно будет воссоздать его на отдельной странице.)

если вы хотите отключить прокрутки #app контейнер, просто добавьте touch-action: none;.

попробуй такое

var mywindow = $('body'), navbarCollap = $('.navbar-collapse');    
navbarCollap.on('show.bs.collapse', function(x) {
                mywindow.css({visibility: 'hidden'});
                $('body').attr("scroll","no").attr("style", "overflow: hidden");
            });
            navbarCollap.on('hide.bs.collapse', function(x) {
                mywindow.css({visibility: 'visible'});
                $('body').attr("scroll","yes").attr("style", "");
            });

в моем случае ни одно из этих решений не сработало на iPhone (iOS 11.0).

единственное эффективное исправление, которое работает на всех моих устройствах это - Иос-10-сафари-предотвратить прокрутки-за-а-фиксированный верхний слой-и-сохранить-свиток-позиция

используйте ниже код для отключения и включения полосы прокрутки.

Scroll = (
    function(){
          var x,y;
         function hndlr(){
            window.scrollTo(x,y);
            //return;
          }  
          return {

               disable : function(x1,y1){
                    x = x1;
                    y = y1;
                   if(window.addEventListener){
                       window.addEventListener("scroll",hndlr);
                   } 
                   else{
                        window.attachEvent("onscroll", hndlr);
                   }     

               },
               enable: function(){
                      if(window.removeEventListener){
                         window.removeEventListener("scroll",hndlr);
                      }
                      else{
                        window.detachEvent("onscroll", hndlr);
                      }
               } 

          }
    })();
 //for disabled scroll bar.
Scroll.disable(0,document.body.scrollTop);
//for enabled scroll bar.
Scroll.enable();

Comments

    Ничего не найдено.