web-dev-qa-db-ja.com

本体のスクロールを防ぎますが、オーバーレイスクロールを許可します

私はこれを可能にする「ライトボックス」タイプの解決策を探していましたが、まだそれを見つけていません(あなたが何かを知っているなら提案してください)。

再作成しようとしている動作は、画像をクリックしたときに Pinterest に表示されるのとまったく同じです。オーバーレイはスクロール可能です(オーバーレイ全体はページの上にあるページのように上に移動します)が、本体 後ろ オーバーレイは固定されています。

私はCSS(すなわちA divoverflow: hiddenと全ページの上部と本体上のオーバーレイ)でこれを作成しようとし、それがスクロールされてからdivを妨げません。

本文/ページがスクロールしないようにしながらフルスクリーンコンテナ内をスクロールする方法

370
PotatoFro

理論

Pinterestサイトの現在の実装を見ると(将来変更される可能性があります)、オーバーレイを開くと、noscrollクラスがbody要素に適用され、overflow: hiddenが設定されるため、bodyはスクロールできなくなりました。

オーバーレイ(オンザフライで作成されるか、ページ内に既に作成され、display: blockを介して可視化され、違いはありません)には、position : fixedおよびoverflow-y: scrollがあり、topleftright、およびbottomプロパティを0に設定すると、このスタイルにより、オーバーレイがビューポート全体に表示されます。

オーバーレイ内のdivは代わりにposition: staticにあり、表示される垂直スクロールバーはその要素に関連しています。その結果、コンテンツはスクロール可能ですが、オーバーレイは固定されたままです。

ズームを閉じると(display: noneを介して)オーバーレイを非表示にし、javascript(または内部のコンテンツのみ)で完全に削除することもできます。挿入方法はユーザー次第です。

最後のステップとして、noscrollクラスをbodyから削除する必要があります(したがって、オーバーフロープロパティは初期値に戻ります)


コード

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

});

最後に、transitionプロパティに適用されたCSS opacityによるフェードイン効果でオーバーレイが開く別の例を示します。また、padding-rightが適用されて、スクロールバーが消えたときに下にあるテキストのリフローが回避されます。

Codepenの例(フェード)

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; 
}
579
fcalderan

Ios上でのオーバースクロールを防ぎたい場合は、.noscrollクラスに固定の位置を追加できます。

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

bodyoverflow: hidden;を使用しないでください。それは自動的にすべてを一番上までスクロールします。 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;
}

デモ here とソースコード here を参照してください。

更新:

キーボードのスペースバーを使ってページアップ/ダウンしたい場合は、オーバーレイにフォーカスを合わせる必要があります。たとえば、クリックするか、手動でJSのdivの一部がキーボードに応答するようにします。オーバーレイが横に移動しているだけなので、オーバーレイが「オフ」になっているときと同じです。それ以外のブラウザでは、これらは2つの通常のdivであり、なぜそれらのうちの1つに焦点を合わせるべきかわからないでしょう。

37
Lucia

Bodyタグに "overflow:hidden"を追加してもうまくいかないことがあるのは注目に値します。その場合は、htmlタグにもプロパティを追加する必要があります。

html, body {
    overflow: hidden;
}
30
Francisco Hodge

ほとんどの解決策はスクロール位置を維持できないという問題を抱えているので、私は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;
}

/* reset CSS */
body {
  margin: 0;
}
<main class="main-content"></main>

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

overscroll-behavior cssプロパティを使用すると、コンテンツの上部または下部に到達したときにブラウザのデフォルトのオーバーフロースクロール動作をオーバーライドできます。

オーバーレイに以下のスタイルを追加するだけです。

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

Codepenデモ

現在はChrome、Firefox、IEで動作します( caniuse

詳細については、 Google開発者向け記事 を確認してください。

23
Igor Alemasow

選択された答えは正しいですが、いくつかの制限があります。

  • あなたの指で超ハード "飛び"はまだバックグラウンドで<body>をスクロールします
  • モーダルで<input>をタップして仮想キーボードを開くと、今後のスクロールはすべて<body>に移動します。

最初の問題に対する修正はありませんが、2番目の問題に焦点を当てたいと思いました。紛らわしいことに、Bootstrapはキーボードの問題を文書化していましたが、修正の例として http://output.jsbin.com/cacido/quiet を引用し、修正されたと主張しました。

確かに、その例は私のテストではiOS上でうまく動作します。しかし、それを最新のBootstrap(v4)にアップグレードすると壊れます。

両者の違いを理解するために、テストケースを短くしてブートストラップに依存しないようにしました、 http://codepen.io/WestonThayer/pen/bgZxBG

決定要因は奇妙です。キーボードの問題を回避するには、background-colorではない modalを含むルート<div>に設定する and<div>を設定できる別のbackground-colorにネスティングする必要があります。

テストするには、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; */
}
7
Weston

一般的に言えば、子(この場合はオーバーレイ)がスクロールしたときに親(この場合は本文)がスクロールしないようにするには、子が親の兄弟になるようにします。親。親がボディである場合、これは追加のラッピング要素を必要とします。

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

ブラウザのメインスクロールバーで特定のDIVコンテンツをスクロールする を参照してください。

6
NGLN

タッチデバイスの場合は、オーバーレイのラッパーに幅1px、幅101vh、高さ最小の透明divを追加してみてください。次にラッパーに-webkit-overflow-scrolling:touch; overflow-y: auto;を追加します。これは、モバイルサファリをオーバーレイがスクロール可能であると考えさせることによって、身体からのタッチイベントを傍受します。

これがサンプルページです。モバイルサファリで開く: http://www.originalfunction.com/overlay.html

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

4
YarGnawh

IpadとIphoneの自分のページで発生した問題を解決しようとしているこの問題を、私は固定divを画像付きポップアップとして表示しているときにスクロールさせていたことに気づきました。

いくつかの答えは良いです、しかしそれらのどれも私の問題を解決しませんでした。 Christoffer Petterssonによる次のブログ投稿を見つけました。そこに提示された解決策は、私がiOSデバイスに関して抱えていた問題を助け、それが私のスクロール背景問題を助けました。

iOS Safariのラバーバンドスクロールについて学んだ6つのこと

それが示唆されたように、私はリンクが時代遅れになる場合に備えてブログ記事の主要なポイントを含みます。

msgstr ""メニューが開いている間にユーザが背景ページをスクロールできることを無効にするためには、JavaScriptとCSSクラスを適用することによって、どの要素がスクロールを許可されるべきかどうかを制御できます。

この Stackoverflow answerに基づいて、disable-scrollingを持つ要素は、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();
    }
};

そして、ページdivにスクロール不可のクラスを追加します。

<div class="page disable-scrolling">
3

以前の回答に追加したいのですが、これをやろうとしましたが、本文をpositionに切り替えるとすぐにレイアウトが壊れてしまいました:fixed。それを避けるために、私は体の高さも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");
}
1

次の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");

1
Damir Kotoric

Body/html scrollを停止したい場合は、以下のように追加してください。

_ css _

    html, body {
        height: 100%;
    }

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

_ html _

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

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

基本的に、あなたはJSなしでそれをすることができます。

主なアイデアは、高さ:100%、オーバーフロー:自動でHTML /ボディを追加することです。オーバーレイの内側では、要件に応じてスクロールを有効または無効にすることができます。

お役に立てれば!

0
Ashwin

意図がモバイル/タッチデバイスで無効にすることであるならば、それをする最も簡単な方法は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;を追加するだけです。

0
Gajus

防止したい動作はスクロールチェーンと呼ばれます。無効にするには

overscroll-behavior: contain;

cSSのオーバーレイに。

0
黄雨伞

これを試して

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", "");
            });
0
Junaid