DIV要素をスクロールするときにページのスクロールを防ぐ方法は?


94

div内での本体のスクロールを防止するためのさまざまな機能を確認してテストし、機能するはずの機能を組み合わせました。

$('.scrollable').mouseenter(function() {
    $('body').bind('mousewheel DOMMouseScroll', function() {
        return false;
    });
    $(this).bind('mousewheel DOMMouseScroll', function() {
        return true;
    });
});
$('.scrollable').mouseleave(function() {
    $('body').bind('mousewheel DOMMouseScroll', function() {
        return true;
    });
});
  • これはすべてのスクロールを停止します。コンテナ内でスクロールを可能にしたいので、
  • これは、マウスを離しても無効になりません

これを行うためのアイデア、またはより良い方法は?


uマウスホイールからfalseを返すようにボディを設定します。おそらくこれが問題です。コンテナがボディの右側にあると思います
Ricardo Binns

@ric_bfaはい、しかしそれを修正する方法
RIK

代わりに本文、クラス/ IDコンテナーを設定
Ricardo Binns

おそらく私は明確にする必要があります。マウスが要素「.scrollable」内にある場合、ボディのスクロール機能を無効にする必要があります
RIK

4
すべてのCSSでJavaScriptなしでこれを行う方法はありませんか?
chharvey、2012年

回答:


165

更新2:私の解決策は、ブラウザーのネイティブスクロールを完全に無効にし(カーソルがDIV内にある場合)、JavaScriptを使用して(.scrollTopプロパティを設定することにより)DIVを手動でスクロールすることです。代替のIMOより優れたアプローチは、ページのスクロールを防止するためにブラウザーのスクロールを選択的に無効にするだけで、DIVのスクロールを無効にすることです。このソリューションを示す以下のRudieの回答を確認してください。


どうぞ:

$( '.scrollable' ).on( 'mousewheel DOMMouseScroll', function ( e ) {
    var e0 = e.originalEvent,
        delta = e0.wheelDelta || -e0.detail;

    this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30;
    e.preventDefault();
});

ライブデモ: https : //jsbin.com/howojuq/edit?js,output

したがって、手動でスクロール位置を設定し、デフォルトの動作(DIVまたはWebページ全体をスクロールすること)を回避します。

更新1: Chrisが以下のコメントで述べたように、jQueryの新しいバージョンでは、デルタ情報は.originalEventオブジェクト内にネストされます。つまり、jQueryはそれをカスタムイベントオブジェクトで公開しないため、代わりにネイティブイベントオブジェクトから取得する必要があります。 。


2
@RobinKnightいいえ、そうではありません。ここで働いてデモです:jsfiddle.net/XNwbt/1こことは、それらの線でデモが削除されます。jsfiddle.net/XNwbt/2
サイムVIDAS

1
Firefox 10では、少なくともLinuxとMacでは手動でのスクロールが逆方向です。あなたがそれを作れば-e.detailFirefox(Mac、Linux)、Safari(Mac)、およびChromium(Linux)でテストされた場合、正しく動作するようです。
Anomie

1
@Anomieそうです。Mozillaの.detail符号は.wheelData(Chrome / IEが持っている)符号と一致しないため、手動で反転する必要があります。私の答えを修正してくれてありがとう。
サイムVIDAS

8
私はこれを使いました、ありがとう!私はこれを追加する必要がありました:if( e.originalEvent ) e = e.originalEvent;
Nikso

2
@ŠimeVidasソフトウェアに実装した後、これを調整しました。重要ではありませんが、要素にスクロールがない場合にデッドロックスクロールを防ぐために、スクロールプロパティの健全性チェックを追加する可能性があります。if ( $(this)[0].scrollHeight !== $(this).outerHeight() ) { //yourcode }スクロールバーがある場合にのみ実行されます。
user0000001 2013

30

古いIEバージョン(<8)との互換性を気にしない場合は、カスタムjQueryプラグインを作成して、オーバーフロー要素で呼び出すことができます。

このソリューションは、スクロールビヘイビアーを上書きしないため、提案された1つのime Vidasよりも優れています-適切な場合にブロックするだけです。

$.fn.isolatedScroll = function() {
    this.bind('mousewheel DOMMouseScroll', function (e) {
        var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.detail,
            bottomOverflow = this.scrollTop + $(this).outerHeight() - this.scrollHeight >= 0,
            topOverflow = this.scrollTop <= 0;

        if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) {
            e.preventDefault();
        }
    });
    return this;
};

$('.scrollable').isolatedScroll();

2
ありがとう!デフォルトの動作を上書きしない方が適切だと思います。ブラウザー間のサポートには、jQueryマウスホイールプラグインを使用できます。
Meettya

残念ながら、これはChrome 52(OSX 10.10)では問題があるようです。ただし、Safariでは完全に動作します。
冷たい

1
ありがとうございました!他のソリューションは、スクロールが超スロー作られ、バギー
agrublev

@wojcikstefan、私はこの警告をクロムで受け取ります:[Violation] Added non-passive event listener to a scroll-blocking 'mousewheel' event. Consider marking event handler as 'passive' to make the page more responsive.
Syed

21

マウススクロールイベントを時々キャンセルすることは可能だと思います:http ://jsfiddle.net/rudiedirkx/F8qSq/show/

$elem.on('wheel', function(e) {
    var d = e.originalEvent.deltaY,
        dir = d < 0 ? 'up' : 'down',
        stop = (dir == 'up' && this.scrollTop == 0) || 
               (dir == 'down' && this.scrollTop == this.scrollHeight-this.offsetHeight);
    stop && e.preventDefault();
});

イベントハンドラー内では、次のことを知る必要があります。


  • d = e.originalEvent.deltaY, dir = d < 0 ? 'up' : 'down' 正の数は下にスクロールすることを意味するため、スクロール方向

  • scrollTop上、scrollHeight - scrollTop - offsetHeight下のスクロール位置

もしあなたが〜なら

  • 上にスクロール、およびtop = 0、または
  • 下にスクロールし、 bottom = 0

イベントをキャンセル: e.preventDefault()そしておそらくe.stopPropagation())。

ブラウザのスクロール動作を上書きしない方がいいと思います。該当する場合のみキャンセルしてください。

これは完全なxbrowserではありませんが、それほど難しくはありません。たぶんマックのデュアルスクロール方向はトリッキーですが...


2
デバイス(タブレット/電話)に同じ機能を実装するにはどうすればよいですか?touchmoveはバインディングイベントだと思います
ViVekH

6

以下のCSSプロパティ overscroll-behavior: contain;を子要素に使用


このネイティブCSSルールと比較すると、他のすべてのソリューションは過剰です。よくできました。
TechWisdom

3

これがあなたを助けるかどうか見てください:

デモ:jsfiddle

$('#notscroll').bind('mousewheel', function() {
     return false
});

編集:

これを試して:

    $("body").delegate("div.scrollable","mouseover mouseout", function(e){
       if(e.type === "mouseover"){
           $('body').bind('mousewheel',function(){
               return false;
           });
       }else if(e.type === "mouseout"){
           $('body').bind('mousewheel',function(){
               return true;
           });
       }
    });

あなたの要素は分離していますが、私のものは他のものに含まれています。
RIK 2009

3

私の意見では、あまりハックされていない解決策は、スクロール可能なdivの上にマウスを置くと、オーバーフローをボディに非表示に設定することです。これにより、ボディのスクロールが防止されますが、不要な「ジャンプ」効果が発生します。次の解決策はそれを回避します:

jQuery(".scrollable")
    .mouseenter(function(e) {
        // get body width now
        var body_width = jQuery("body").width();
        // set overflow hidden on body. this will prevent it scrolling
        jQuery("body").css("overflow", "hidden"); 
        // get new body width. no scrollbar now, so it will be bigger
        var new_body_width = jQuery("body").width();
        // set the difference between new width and old width as padding to prevent jumps                                     
        jQuery("body").css("padding-right", (new_body_width - body_width)+"px");
    })
    .mouseleave(function(e) {
        jQuery("body").css({
            overflow: "auto",
            padding-right: "0px"
        });
    })

必要に応じて、コードをよりスマートにすることができます。たとえば、ボディにすでにパディングがあるかどうかをテストし、パディングがある場合は、新しいパディングを追加することができます。


3

上記のソリューションでは、Firefoxに関して少し間違いがあります。Firefoxの「DOMMouseScroll」イベントにはe.detailプロパティがありません。このプロパティを取得するには、次の 'e.originalEvent.detail'を記述してください。

以下は、Firefoxの実用的なソリューションです。

$.fn.isolatedScroll = function() {
    this.on('mousewheel DOMMouseScroll', function (e) {
        var delta = e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.originalEvent.detail,
            bottomOverflow = (this.scrollTop + $(this).outerHeight() - this.scrollHeight) >= 0,
            topOverflow = this.scrollTop <= 0;

        if ((delta < 0 && bottomOverflow) || (delta > 0 && topOverflow)) {
            e.preventDefault();
        }
    });
    return this;
};

これは、divの一番上または一番下にクラッシュした場合を除いて、非常にうまく機能します。最初のイベントが本体に持ち込まれます。OSXでのクロムの2本指タッチによるテスト。
johnb003 2017年

3

ここでは、ブラウザのネイティブスクロールを破壊しないjQueryなしのシンプルなソリューション(これは:人工的/醜いスクロールではありません):

var scrollable = document.querySelector('.scrollable');

scrollable.addEventListener('wheel', function(event) {
    var deltaY = event.deltaY;
    var contentHeight = scrollable.scrollHeight;
    var visibleHeight = scrollable.offsetHeight;
    var scrollTop = scrollable.scrollTop;

    if (scrollTop === 0 && deltaY < 0)
        event.preventDefault();
    else if (visibleHeight + scrollTop === contentHeight && deltaY > 0)
        event.preventDefault();
});

ライブデモ:http : //jsfiddle.net/ibcaliax/bwmzfmq7/4/


私は上記のコードを実行するNPMライブラリを公開した。npmjs.com/package/dontscrollthebody
イニャキバズカスティージョ

2

これが私がアプリケーションで使用した私のソリューションです。

本文のオーバーフローを無効にし、Webサイト全体のHTMLをコンテナーdiv内に配置しました。Webサイトのコンテナーがオーバーフローしているため、ユーザーは期待どおりにページをスクロールできます。

次に、Webサイト全体をカバーする、より高いZインデックスを持つ兄弟div(#Prevent)を作成しました。#Preventの方がZインデックスが高いため、Webサイトコンテナーと重複しています。#Preventが表示されているときは、マウスがWebサイトコンテナーの上に移動していないため、スクロールできません。

もちろん、モーダルなど、#PreventよりもZインデックスが高い別のdivをマークアップに配置することもできます。これにより、スクロールの問題のないポップアップウィンドウを作成できます。

このソリューションは、スクロールバーを非表示にしないため、より効果的です(ジャンプ効果)。イベントリスナーを必要とせず、実装も簡単です。IE7と8では(特定のコードによって異なりますが)プレイバックする必要がありますが、すべてのブラウザーで機能します。

html

<body>
  <div id="YourModal" style="display:none;"></div>
  <div id="Prevent" style="display:none;"></div>
  <div id="WebsiteContainer">
     <div id="Website">
     website goes here...
     </div>
  </div>
</body>

CSS

body { overflow: hidden; }

#YourModal {
 z-index:200;
 /* modal styles here */
}

#Prevent {
 z-index:100;
 position:absolute;
 left:0px;
 height:100%;
 width:100%;
 background:transparent;
}

#WebsiteContainer {
  z-index:50;
  overflow:auto;
  position: absolute;
  height:100%;
  width:100%;
}
#Website {
  position:relative;
}

jquery / js

function PreventScroll(A) { 
  switch (A) {
    case 'on': $('#Prevent').show(); break;
    case 'off': $('#Prevent').hide(); break;
  }
}

スクロールを無効/有効にします

PreventScroll('on'); // prevent scrolling
PreventScroll('off'); // allow scrolling

2
単にコードを投稿するのではなく、回答に関する情報を含めることを検討してください。私たちは「修正」を提供するだけでなく、人々が学ぶのを助けることを試みます。元のコードの何が間違っていたのか、何が違ったのか、なぜ変更が機能したのかを説明する必要があります。
アンドリューバーバー

1

このイベントを、スクロールバーのある複数の要素に追加する必要がありました。スクロールバーが存在しない場合、メインのスクロールバーは正常に機能しませんでした。だから私は次のように@ smallimeコードに小さな変更を加えました:

$( '.scrollable' ).on( 'mousewheel DOMMouseScroll', function ( e ) {
    if($(this).prop('scrollHeight') > $(this).height())
    {
        var e0 = e.originalEvent, delta = e0.wheelDelta || -e0.detail;

        this.scrollTop += ( delta < 0 ? 1 : -1 ) * 30;
        e.preventDefault();
    }       
});

現在、スクロールバーのある要素のみがメインスクロールの停止を妨げます。


0

Vidasの答えの純粋なJavaScriptバージョンel$は、スクロールしている飛行機のDOMノードです。

function onlyScrollElement(event, el$) {
    var delta = event.wheelDelta || -event.detail;
    el$.scrollTop += (delta < 0 ? 1 : -1) * 10;
    event.preventDefault();
}

複数回も取り付けないようにしてください。ここに例があります

var ul$ = document.getElementById('yo-list');
// IE9, Chrome, Safari, Opera
ul$.removeEventListener('mousewheel', onlyScrollElement);
ul$.addEventListener('mousewheel', onlyScrollElement);
// Firefox
ul$.removeEventListener('DOMMouseScroll', onlyScrollElement);
ul$.addEventListener('DOMMouseScroll', onlyScrollElement);

注意:関数をアタッチする前に毎回関数を再初期化する場合、関数は定数である必要があります。var func = function (...)これremoveEventListenerは機能しません。


0

JavaScriptなしでこれを行うことができます。position: fixedとの両方のdivでスタイルを設定できoverflow-y: autoます。z-index(オーバーラップしている場合)を設定して、一方を他方より高くする必要がある場合があります。

ここだCodePen上の基本的な例が


0

これは、特定のdivをスクロールしているときに親のスクロールを防止するのに役立つプラグインで、さまざまなオプションを操作できます。

ここでそれをチェックしてください:

https://github.com/MohammadYounes/jquery-scrollLock

使用法

JavaScriptを介してスクロールロックをトリガーする:

$('#target').scrollLock();

マークアップを介してスクロールロックをトリガー:

    <!-- HTML -->
<div data-scrollLock
     data-strict='true'
     data-selector='.child'
     data-animation='{"top":"top locked","bottom":"bottom locked"}'
     data-keyboard='{"tabindex":0}'
     data-unblock='.inner'>
     ...
</div>

<!-- JavaScript -->
<script type="text/javascript">
  $('[data-scrollLock]').scrollLock()
</script>

デモを見る


0

ユーザーが明らかな変更について否定的な経験をすることはないと思われる場合は、これを可能な解決策として提供するだけです。マウスがターゲットdivの上にあるときに、ボディのオーバーフローのクラスを非表示に変更しました。次に、マウスが離れると、ボディのdivを非表示のオーバーフローに変更しました。

個人的には見た目が悪いとは思わない、私のコードはトグルを使用してそれをよりきれいにすることができ、ユーザーに気付かれずにこの効果を可能にすることには明らかな利点があります。したがって、これはおそらくハッキングの最後の手段です。

//listen mouse on and mouse off for the button
pxMenu.addEventListener("mouseover", toggleA1);
pxOptContainer.addEventListener("mouseout", toggleA2);
//show / hide the pixel option menu
function toggleA1(){
  pxOptContainer.style.display = "flex";
  body.style.overflow = "hidden";
}
function toggleA2(){
  pxOptContainer.style.display = "none";
  body.style.overflow = "hidden scroll";
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.