モーダルを開いたときにBODYがスクロールしないようにする


346

Webサイトのモーダル(http://twitter.github.com/bootstrapから)を開いているときにマウスホイールを使用しているときに、体のスクロールを停止したいのですが。

モーダルが開かれたときに以下のJavaScriptを呼び出そうとしましたが、成功しませんでした

$(window).scroll(function() { return false; });

そして

$(window).live('scroll', function() { return false; });

私たちのウェブサイトはIE6のサポートを落としましたが、IE7 +は互換性がある必要があります。

回答:


468

ブートストラップは、モーダルダイアログが表示されるとmodalクラスmodal-openをボディに自動的に追加し、ダイアログが非表示になるとクラスを削除します。したがって、CSSに以下を追加できます。

body.modal-open {
    overflow: hidden;
}

上記のコードはBootstrap CSSコードベースに属していると主張することもできますが、これはサイトに追加する簡単な修正です。

2013年2月8日更新
これはTwitter Bootstrap v。2.3.0での動作を停止しました。modal-openクラスを本文に追加しなくなりました。

回避策は、モーダルが表示されようとしているときにボディにクラスを追加し、モーダルが閉じているときにクラスを削除することです。

$("#myModal").on("show", function () {
  $("body").addClass("modal-open");
}).on("hidden", function () {
  $("body").removeClass("modal-open")
});

2013年3月11日更新modal-openスクロールを防止する目的で 、クラスがBootstrap 3.0で明示的に戻るように見えます。

本体に.modal-openを再導入します(スクロールをそこに挿入できるようにするため)

これを見てくださいhttps : //github.com/twitter/bootstrap/pull/6342- モーダルセクションを見てください


2
これは、ブートストラップ2.2.2では機能しなくなりました。うまくいけば、.modal-openが将来戻ってくるでしょう... github.com/twitter/bootstrap/issues/5719
ppetrid

2
@ppetrid戻るとは思わない。この記述に基づきます:github.com/twitter/bootstrap/wiki/Upcoming-3.0-changes(下部をご覧ください)。引用:「内部のモーダルスクロールはもうありません。代わりに、モーダルはコンテンツを格納するように拡大し、ページスクロールはモーダルを格納します。」
MartinHN

2
@Bagata Cool- modal-openBootstrap 3に戻りますので、起動したら上記のコードを削除しても安全です。
MartinHN 2013年

2
スクロールダウンを続ける必要があるのはこのためです。選択した回答で満足できない場合は、このような宝石を見つける可能性があります。97票以上の回答があまり好まれていないコメントの下に埋もれているとは期待していませんでした。
Mohd Abdul Mujib 2014年

2
これの問題は、モーダルを開いたときにドキュメントが上にスクロールしないようにするために、body.modal-open {overflow:visible}を追加する必要があることです。あなたの解決策は現時点で機能し、モーダルが開かれるとドキュメントが上にスクロールするという欠点があります
patrick

120

承認された回答はモバイル(少なくともiOS 7 w / Safari 7)では機能せず、CSSが機能するときに私のサイトでMOAR JavaScriptを実行したくありません。

このCSSは、モーダルの下で背景ページがスクロールしないようにします。

body.modal-open {
    overflow: hidden;
    position: fixed;
}

ただし、基本的に上部にスクロールするというわずかな副作用もあります。position:absoluteこれを解決しますが、モバイルでスクロールする機能を再導入します。

ビューポート(ビューポートをに追加するための私のプラグイン)<body>がわかっている場合は、のcssトグルを追加するだけpositionです。

body.modal-open {
    // block scroll for mobile;
    // causes underlying page to jump to top;
    // prevents scrolling on all screens
    overflow: hidden;
    position: fixed;
}
body.viewport-lg {
    // block scroll for desktop;
    // will not jump to top;
    // will not prevent scroll on mobile
    position: absolute; 
}

また、これを追加して、モーダルを表示/非表示にするときに基本ページが左/右にジャンプしないようにします。

body {
    // STOP MOVING AROUND!
    overflow-x: hidden;
    overflow-y: scroll !important;
}

この答えはx-postです。


7
ありがとう!モバイル(少なくともiOSとAndroidのネイティブブラウザ)は頭痛の種でありposition: fixed、身体なしでは機能しません。
Raul Rene

モーダルの表示/非表示時にページが左/右にジャンプするのを防ぐためのコードも含めてくれてありがとう。これは非常に便利で、iOS 9.2.1を実行しているiPhone 5cのSafariで発生していた問題が修正されることを確認しました。
Elijah Lofgren 2016

6
上へのスクロールを修正するには、クラスを追加する前に位置を記録し、クラスが削除された後、記録された位置にwindow.scrollを実行します。これは私が自分で修正した方法です:pastebin.com/Vpsz07zd
ツール

これは非常に基本的なニーズにのみ当てはまると思いますが、便利な修正でした。ありがとう。
スティーブベナー

32

ボディオーバーフローを非表示にすると、ボディがスクロールしなくなります。モーダルを非表示にしたら、自動に戻します。

これがコードです:

$('#adminModal').modal().on('shown', function(){
    $('body').css('overflow', 'hidden');
}).on('hidden', function(){
    $('body').css('overflow', 'auto');
})

優秀な!これは私を助けました。ありがとう。
pfcodesは

21

あなたはオーバーフローでボディサイズをウィンドウサイズに設定してみることができます:モーダルが開いているときは非表示


12
これを行うと、モーダルが開かれるたびに画面が移動します。これは便利ではありません。背景のスクロールを無効にする必要があるだけです
xorinzor

スクロールバーがブラウザに関連していて、スクロールバーで多くのことを行うことができないかどうかわからない
charlietfl

モーダルを「固定」に設定して、スクロールしても動かないようにすることができます
charlietfl

8
モーダルのスクロールを停止することではなく、背景のボディのスクロールを停止することについてです
xorinzor

1
ボディがオーバーフローした場合にスクロールするのはウィンドウです。たとえば、スクロールバーはドキュメントの一部ではありません。
charlietfl 2012年

18

@charlietflの回答を超えてスクロールバーを考慮する必要があります。そうしないと、ドキュメントがリフローする可能性があります。

モーダルを開く:

  1. body幅を記録する
  2. セットbodyへのオーバーフローhidden
  3. ボディの幅をステップ1の幅に明示的に設定します。

    var $body = $(document.body);
    var oldWidth = $body.innerWidth();
    $body.css("overflow", "hidden");
    $body.width(oldWidth);

モーダルを閉じる:

  1. セットbodyへのオーバーフローauto
  2. セットbodyの幅auto

    var $body = $(document.body);
    $body.css("overflow", "auto");
    $body.width("auto");

着想:http : //jdsharp.us/jQuery/minute/calculate-scrollbar-width.php


より適切な用語がないために「ジャンプ」画面が表示されていましたが、ここで重要なのは幅の設定に従うことでした。トンありがとう。
Hcabnettek 2013

1
@Hcabnettekうん:「ジャンプ」==「ドキュメントのリフロー」。それがあなたを助けてくれてうれしい!:-)
jpap 2013

これのためのCSSソリューションはありますか?すべてのブラウザとモバイルで機能しますか?
ルーベン

単なるタイプミス:それ$body.css("overflow", "auto");は最後のステップである必要があります:)
schneikai

ああ、なんて素晴らしいアイデアでしょう。@jpapは、長い間私を悩ませていたドキュメントのリフローの問題の解決を助けてくれました。
Goran Radulovic

17

警告:以下のオプションはBootstrap v3.0.xには関係ありません。これらのバージョンでのスクロールはモーダル自体に明示的に限定されているためです。ホイールイベントを無効にすると、ビューポートの高さよりも高い高さのモーダルで一部のユーザーがコンテンツを表示するのを誤って防止する可能性があります。


さらに別のオプション:ホイールイベント

スクロールイベントはキャンセルできません。ただし、マウスホイールホイールのイベントをキャンセルすることは可能です。重要な注意点は、すべてのレガシーブラウザがそれらをサポートしているわけではないことです。Mozillaは最近、Gecko 17.0で後者のサポートを追加しました。完全な広がりはわかりませんが、IE6 +とChromeではサポートされています。

それらを活用する方法は次のとおりです。

$('#myModal')
  .on('shown', function () {
    $('body').on('wheel.modal mousewheel.modal', function () {
      return false;
    });
  })
  .on('hidden', function () {
    $('body').off('wheel.modal mousewheel.modal');
  });

JSFiddle


JSFiddleは、Firefox 24、Chrome 24、IE9では機能しません。
AxeEffect 2013

@AxeEffectが動作するはずです。唯一の問題は、Bootstrapライブラリへの外部参照が変更されたことです。ヘッドアップをありがとう。
merv

2
これにより、タッチデバイスのスクロールが妨げられることはありませんoverflow:hidden。今のところ、これが適しています。
Webinan 2014

5
それらはすべて動作していますが、モバイルデバイスでは動作しません。-__- Android 4.1およびChromeでテスト済み
Tower Jimmy

@TowerJimmyおそらくタッチイベントまたはドラッグイベントをキャンセルする必要があります(それが可能な場合でも)
xorinzor

9
/* =============================
 * Disable / Enable Page Scroll
 * when Bootstrap Modals are
 * shown / hidden
 * ============================= */

function preventDefault(e) {
  e = e || window.event;
  if (e.preventDefault)
      e.preventDefault();
  e.returnValue = false;  
}

function theMouseWheel(e) {
  preventDefault(e);
}

function disable_scroll() {
  if (window.addEventListener) {
      window.addEventListener('DOMMouseScroll', theMouseWheel, false);
  }
  window.onmousewheel = document.onmousewheel = theMouseWheel;
}

function enable_scroll() {
    if (window.removeEventListener) {
        window.removeEventListener('DOMMouseScroll', theMouseWheel, false);
    }
    window.onmousewheel = document.onmousewheel = null;  
}

$(function () {
  // disable page scrolling when modal is shown
  $(".modal").on('show', function () { disable_scroll(); });
  // enable page scrolling when modal is hidden
  $(".modal").on('hide', function () { enable_scroll(); });
});

9

CSSを変更しただけではChromeで動作しませんでした。ページを上にスクロールして戻したくなかったためです。これはうまくいきました:

$("#myModal").on("show.bs.modal", function () {
  var top = $("body").scrollTop(); $("body").css('position','fixed').css('overflow','hidden').css('top',-top).css('width','100%').css('height',top+5000);
}).on("hide.bs.modal", function () {
  var top = $("body").position().top; $("body").css('position','relative').css('overflow','auto').css('top',0).scrollTop(-top);
});

1
これは、私にとってbootstrap 3.2で機能した唯一のソリューションです。
volx757 2016

1
アンギュラーマテリアルサイドナビで一番上の問題にジャンプしました。これは、すべてのケースで機能するように見える唯一の回答でした(デスクトップ/モバイル+モーダル/サイドナビゲーションでスクロールを許可+ジャンプせずに本体のスクロール位置を固定したままにします)。
cYrixmorten 2017

これも実際に私のために働いた唯一の解決策です。tx
Deedz 2018

私のために働いた、ブートストラップv4
Deano

9

これを試してください:

.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
    height: 100%;
}

それは私のために働いた。(IE8をサポート)


4
これは機能しますが、を使用してposition: fixedいるときにモーダルを開いたときにトップにジャンプすることにもなります。
AlexioVay 2016

8

以下のためにブートストラップは、この(に取り組んでみてくださいFirefoxChromeとのMicrosoft Edge):

body.modal-open {
    overflow: hidden;
    position:fixed;
    width: 100%;
}

お役に立てれば...


7

クラス「is-modal-open」を追加するか、JavaScriptでbodyタグのスタイルを変更しても問題ありません。しかし、私たちが直面する問題は、ボディがオーバーフローになったときです:非表示、上にジャンプします(scrollTopは0になります)。これは後でユーザビリティの問題になります。

この問題の解決策として、bodyタグのオーバーフローを変更する代わりに、htmlタグで変更します。

$('#myModal').on('shown.bs.modal', function () {
  $('html').css('overflow','hidden');
}).on('hidden.bs.modal', function() {
  $('html').css('overflow','auto');
});

1
一般的なコンセンサスの回答はページを一番上にスクロールするので、これは完全に正しい回答です。これは恐ろしいユーザーエクスペリエンスです。これについてブログを書いてください。これをグローバルソリューションに変えてしまいました。
スミス

これはiPhoneでは機能しません。
BadriNarayanan Sridharan

6

このコードについてはわかりませんが、試してみる価値はあります。

jQueryの場合:

$(document).ready(function() {
    $(/* Put in your "onModalDisplay" here */)./* whatever */(function() {
        $("#Modal").css("overflow", "hidden");
    });
});

前に言ったように、100%確実ではありませんが、とにかくやってみてください。


1
これは、モーダルが開かれている間にボディがスクロールするのを妨げません
xorinzor

@xorinzorはcharlietflの回答のコメントセクションでこれが機能すると述べました。しかし、あなたが言った:これは、モーダルが開かれている間、ボディがスクロールするのを妨げません。
アニッシュグプタ

真実ですが、今のところそれが部分的に機能する唯一のソリューションであり、私は大丈夫です。私が彼の回答を回答としてマークした理由は、彼が回答を以前に持っていたからです。
xorinzor

@xorinzor本当に、私は彼/彼女の前に私が答えたと思っていました、いくつかの奇妙な不具合かもしれません。
それでも

5

2017年11月の時点でChromeは新しいcssプロパティを導入しました

overscroll-behavior: contain;

これにより、この問題が解決されます。ただし、執筆時点では、クロスブラウザーのサポートは制限されています。

詳細とブラウザのサポートについては、以下のリンクを参照してください


4

最良のソリューションは、body{overflow:hidden}これらの回答のほとんどで使用されているcssのみのソリューションです。一部の回答は、スクロールバーの非表示によって引き起こされる「ジャンプ」も防ぐ修正を提供しています。しかし、どれもエレガントすぎませんでした。したがって、私はこれら2つの関数を作成しましたが、それらはかなりうまく機能しているようです。

var $body = $(window.document.body);

function bodyFreezeScroll() {
    var bodyWidth = $body.innerWidth();
    $body.css('overflow', 'hidden');
    $body.css('marginRight', ($body.css('marginRight') ? '+=' : '') + ($body.innerWidth() - bodyWidth))
}

function bodyUnfreezeScroll() {
    var bodyWidth = $body.innerWidth();
    $body.css('marginRight', '-=' + (bodyWidth - $body.innerWidth()))
    $body.css('overflow', 'auto');
}

このjsFiddleをチェックして、使用されていることを確認してください。


これはそれほど古いものではありませんが、私がまだウィンドウをスクロールできるというフィドルでさえ、私にはまったく機能していません。何が欠けていますか?
着陸

モーダルを数回開いて閉じると、メインの緑のDIVが収縮します。
Webinan 2014

@Webinan Win7のChromeでは表示されません。ブラウザとビューポートのサイズは?
スティーブンM.ハリス

1
約20回開閉した後の@smhmicは、緑のdivの幅がopen modalボタンの幅と等しくなります。Chrome on 8
Webinan 2014

@jpapの回答(stackoverflow.com/a/16451821/5516499)に似ていますが、バグが追加されています。:-(
Kivi Shapiro

4

多くの人が本文に「オーバーフロー:非表示」を提案していますが、これはWebサイトを一番上にスクロールさせるため、機能しません(少なくとも私の場合は機能しません)。

これは、jQueryを使用して私(携帯電話とコンピューターの両方)で機能するソリューションです。

    $('.yourModalDiv').bind('mouseenter touchstart', function(e) {
        var current = $(window).scrollTop();
        $(window).scroll(function(event) {
            $(window).scrollTop(current);
        });
    });
    $('.yourModalDiv').bind('mouseleave touchend', function(e) {
        $(window).off('scroll');
    });

これにより、モーダルのスクロールが機能し、同時にWebサイトがスクロールされなくなります。


この解決策のように見えますが、これもiOSのバグが修正されています。hackernoon.com/...を
ゴテンクス

3

あなたは次のロジックを使うことができました、私はそれをテストし、それは動作します(IEでも)

   <html>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">

var currentScroll=0;
function lockscroll(){
    $(window).scrollTop(currentScroll);
}


$(function(){

        $('#locker').click(function(){
            currentScroll=$(window).scrollTop();
            $(window).bind('scroll',lockscroll);

        })  


        $('#unlocker').click(function(){
            currentScroll=$(window).scrollTop();
            $(window).unbind('scroll');

        })
})

</script>

<div>

<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<button id="locker">lock</button>
<button id="unlocker">unlock</button>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>

</div>

2

私は100%じゃないことを確認これはブートストラップで動作しますが、試してみる価値-それはgithubの上で見つけることができRemodal.jsと協力:http://vodkabears.github.io/remodal/、それは方法のために理にかなっていますかなり似ています。

ページが最上部にジャンプするのを停止し、コンテンツの右シフトも防止するbodyには、モーダルが発生したときににクラスを追加し、次のCSSルールを設定します。

body.with-modal {
    position: static;
    height: auto;
    overflow-y: hidden;
}

コンテンツの右側へのジャンプを停止するのは、position:staticheight:autoです。overflow-y:hidden;モーダル背後スクロール可能であることからページを停止します。


このソリューションは、Safari 11.1.1、Chrome 67.0.3396.99、Firefox 60.0.2で完全に機能します。ありがとう!
Dom

2

このフィドルに基づく:http : //jsfiddle.net/dh834zgw/1/

次のスニペット(jqueryを使用)は、ウィンドウのスクロールを無効にします。

 var curScrollTop = $(window).scrollTop();
 $('html').toggleClass('noscroll').css('top', '-' + curScrollTop + 'px');

そしてあなたのCSSで:

html.noscroll{
    position: fixed;
    width: 100%;
    top:0;
    left: 0;
    height: 100%;
    overflow-y: scroll !important;
    z-index: 10;
 }

モーダルを削除するときは、htmlタグのnoscrollクラスを削除することを忘れないでください。

$('html').toggleClass('noscroll');

overflowに設定すべきではありませんhiddenか?これは私のために働いたので+1(を使用してhidden)。
mhulse

2

チェックボックスハックによって生成されたサイドバーがありました。ただし、主なアイデアは、ドキュメントscrollTopを保存し、ウィンドウのスクロール中に変更しないことです。

本文が「オーバーフロー:非表示」になったときにページがジャンプするのが気に入らなかっただけです。

window.addEventListener('load', function() {
    let prevScrollTop = 0;
    let isSidebarVisible = false;

    document.getElementById('f-overlay-chkbx').addEventListener('change', (event) => {
        
        prevScrollTop = window.pageYOffset || document.documentElement.scrollTop;
        isSidebarVisible = event.target.checked;

        window.addEventListener('scroll', (event) => {
            if (isSidebarVisible) {
                window.scrollTo(0, prevScrollTop);
            }
        });
    })

});


2

悲しいことに、上記の答えのどれも私の問題を修正しませんでした。

私の状況では、Webページには元々スクロールバーがあります。モーダルをクリックしても、スクロールバーが消えず、ヘッダーが少し右に移動します。

次に、追加を試みました.modal-open{overflow:auto;}(ほとんどの人が推奨しています)。それは確かに問題を修正しました:モーダルを開いた後にスクロールバーが表示されます。ただし、「ヘッダーの下の背景がモーダルの背後にある別の長いバーと一緒に少し左に移動する」という別の副作用が出ます。

モーダルの後ろの長いバー

幸い、を追加すると{padding-right: 0 !important;}、すべてが完全に修正されます。ヘッダーと本文の両方の背景は移動せず、モーダルは引き続きスクロールバーを保持します。

固定画像

これがまだこの問題で立ち往生している人々を助けることを願っています。幸運を!


1

ほとんどの部分はここにありますが、すべてをまとめた答えはありません。

問題は3つあります。

(1)下にあるページのスクロールを防ぐ

$('body').css('overflow', 'hidden')

(2)スクロールバーを削除する

var handler = function (e) { e.preventDefault() }
$('.modal').bind('mousewheel touchmove', handler)

(3)モーダルが閉じられたときにクリーンアップする

$('.modal').unbind('mousewheel touchmove', handler)
$('body').css('overflow', '')

モーダルがフルスクリーンでない場合は、.modalバインディングをフルスクリーンオーバーレイに適用します。


4
これにより、モーダル内でのスクロールも防止されます。
Daniel

同じ問題。解決策は見つかりましたか?@Daniel
AlexioVay 2016

@Vayソート。:このチェックアウトblog.christoffer.me/...
ダニエル・

1

Bootstrap 3の私のソリューション:

.modal {
  overflow-y: hidden;
}
body.modal-open {
  margin-right: 0;
}

私にとってはoverflow: hiddenbody.modal-openクラスの唯一のメンバーは、元のページが原因でページが左にシフトするのを妨げなかったからmargin-right: 15pxです。


1

私はこのようにそれをやった...

$('body').css('overflow', 'hidden');

しかし、スクローラーが消えると、すべてが20ピクセル右に移動したので、

$('body').css('margin-right', '20px');

その直後。

私のために働く。


これは、モーダルが画面サイズよりも小さい場合にのみ機能します。
セルゲイ、

1

モーダルの高さ/幅が100%の場合、「mouseenter / leave」はスクロールを簡単に有効または無効にするように機能します。これは本当に私にとってうまくいきました:

var currentScroll=0;
function lockscroll(){
    $(window).scrollTop(currentScroll);
} 
$("#myModal").mouseenter(function(){
    currentScroll=$(window).scrollTop();
    $(window).bind('scroll',lockscroll); 
}).mouseleave(function(){
    currentScroll=$(window).scrollTop();
    $(window).unbind('scroll',lockscroll); 
});

1

私のために働いた

$('#myModal').on({'mousewheel': function(e) 
    {
    if (e.target.id == 'el') return;
    e.preventDefault();
    e.stopPropagation();
   }
});

1

ブルマのようにそれをしないのはなぜですか?モーダルがアクティブな場合、オーバーフローする.is-clippedのクラスをhtmlに追加します。hidden!important; 以上です。

編集:オーケー、ブルマにはこのバグがあるため、次のようなものも追加する必要があります

html.is-modal-active {
  overflow: hidden !important;
  position: fixed;
  width: 100%; 
}

1

私にとってこの問題は主にiOSで発生したため、iOSでのみそれを修正するコードを提供します。

  if(!!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform)) {
    var $modalRep    = $('#modal-id'),
        startScrollY = null, 
        moveDiv;  

    $modalRep.on('touchmove', function(ev) {
      ev.preventDefault();
      moveDiv = startScrollY - ev.touches[0].clientY;
      startScrollY = ev.touches[0].clientY;
      var el = $(ev.target).parents('#div-that-scrolls');
      // #div-that-scrolls is a child of #modal-id
      el.scrollTop(el.scrollTop() + moveDiv);
    });

    $modalRep.on('touchstart', function(ev) {
      startScrollY = ev.touches[0].clientY;
    });
  }

1

上記の答えはどれも私にとって完璧に機能しませんでした。だから私はうまくいく別の方法を見つけました。

scroll.(namespace)リスナーとのセットscrollTopdocument最新の値に追加するだけです...

また、閉じるスクリプトでリスナーを削除します。

// in case of bootstrap modal example:
$('#myModal').on('shown.bs.modal', function () {

  var documentScrollTop = $(document).scrollTop();
  $(document).on('scroll.noScroll', function() {
     $(document).scrollTop(documentScrollTop);
     return false;
  });

}).on('hidden.bs.modal', function() {

  $(document).off('scroll.noScroll');

});

更新

どうやら、これはクロムではうまく機能しません。それを修正するための提案はありますか?



0

ブートストラップ3モーダルのスクロールイベントを取得する方法を知りたい場合:

$(".modal").scroll(function() {
    console.log("scrolling!);
});
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.