Scrolling child div scrollt durch das Fenster, wie kann ich das stoppen?

Antworten:

68

Sie können das Scrollen der gesamten Seite inaktivieren, indem Sie Folgendes tun:

<div onmouseover="document.body.style.overflow='hidden';" onmouseout="document.body.style.overflow='auto';"></div>
Teemu
quelle
33
Gut, aber dadurch verschwindet die Bildlaufleiste des Browsers, wenn Sie mit der Maus über das Div fahren.
Stapel
@cstack Sie haben Recht, deshalb ist die Antwort von OP (Jeevan) besser.
Imran Bughio
2
Viele Browser-Scrollräder verschwinden und erscheinen wieder, wenn der Benutzer jetzt die Maus bewegt, sodass der obige Kommentar kein Problem mehr darstellt.
Keith Holliday
Diese Lösung funktioniert jedoch nicht, wenn die Seite in einen Iframe eingebettet ist.
Gautam Krishnan
5
keine Lösung. Wenn Sie den Überlauf auf "Ausgeblendet" setzen, wird die Bildlaufleiste ausgeblendet, die plötzlich den gesamten Inhalt des äußeren Elements neu formatiert. Dies setzt auch voraus, dass das äußere Element ein Körper ist, es könnte sich jedoch auch um ein anderes Bildlauf-Div handeln.
Robisrob
43

Die Lösung gefunden.

http://jsbin.com/itajok

Das brauchte ich.

Und das ist der Code.

http://jsbin.com/itajok/edit#javascript,html

Verwendet ein jQuery-Plug-In.


Update wegen Verfallserklärung

Vom jquery-mousewheel :

Das alte Verhalten der Zugabe von drei Argumente ( delta, deltaX, und deltaY) an den Ereignishandler ist jetzt veraltet und wird in späteren Versionen entfernt werden.

Dann event.deltaYmuss jetzt verwendet werden:

var toolbox = $('#toolbox'),
    height = toolbox.height(),
    scrollHeight = toolbox.get(0).scrollHeight;

toolbox.off("mousewheel").on("mousewheel", function (event) {
  var blockScrolling = this.scrollTop === scrollHeight - height && event.deltaY < 0 || this.scrollTop === 0 && event.deltaY > 0;
  return !blockScrolling;
});

Demo

Jeevan
quelle
6
Ihr Link verwendet Github für die Js und Pausen, weil Inhaltstyp bla bla hier funktioniert: jsbin.com/itajok/207
Michael J. Calkins
Beide jsbins scheinen im Chrome-Geräteemulator und auf dem iPhone nicht zu funktionieren. Weiß jemand, ob das noch funktioniert?
Dirk Boer
2
Ihre "Lösung" funktioniert nur für Maus-Scroll-Ereignisse, nicht für Bild-auf / ab- oder Pfeiltasten.
Scott
Warum ist hier "Aus" erforderlich?
Brad Johnson
16

Die ausgewählte Lösung ist ein Kunstwerk. Ich dachte, es wäre ein Plugin wert ...

$.fn.scrollGuard = function() {
    return this
        .on( 'wheel', function ( e ) {
            var event = e.originalEvent;
            var d = event.wheelDelta || -event.detail;
            this.scrollTop += ( d < 0 ? 1 : -1 ) * 30;
            e.preventDefault();
        });
};    

Dies war für mich eine ständige Unannehmlichkeit und diese Lösung ist im Vergleich zu anderen Hacks, die ich gesehen habe, so sauber. Neugierig zu wissen, wie viel mehr darüber funktioniert und wie weit verbreitet es sein würde, aber ein Hoch auf Jeevan und jeden, der sich das ursprünglich ausgedacht hat. Übrigens - der Stackoverflow-Antworteditor benötigt dies!

AKTUALISIEREN

Ich glaube, das ist insofern besser, als es nicht versucht, das DOM überhaupt zu manipulieren, sondern nur das bedingte Sprudeln verhindert ...

$.fn.scrollGuard2 = function() {
  return this
    .on( 'wheel', function ( e ) {
      var $this = $(this);
      if (e.originalEvent.deltaY < 0) {
        /* scrolling up */
        return ($this.scrollTop() > 0);
      } else {
        /* scrolling down */
        return ($this.scrollTop() + $this.innerHeight() < $this[0].scrollHeight);
      }
    })
  ;
};    

Funktioniert hervorragend in Chrom und ist viel einfacher als andere Lösungen ... lassen Sie mich wissen, wie es anderswo abschneidet ...

GEIGE

Robisrob
quelle
3
Durch Hinzufügen des DOMMouseScroll-Ereignisses funktioniert es mit Firefox → jsfiddle.net/chodorowicz/egqy7mbz/1
chodorowicz
Ich bin überrascht, dass dies nicht in jquery geschrieben ist. Ich dachte, einer der Hauptpunkte war, dass es nicht wichtig ist, welchen Browser Sie verwenden.
Robisrob
eigentlich sieht es so aus, als wheel
wären
Dies führt zu einem merklich ruckeligeren Scrollen in Chrome auf meinem Macbook. Die akzeptierte Lösung hat dieses Problem nicht.
Danvk
enttäuschend. Es gibt so viele verschiedene Versionen davon. scheint ein wichtiger Aspekt der Benutzeroberfläche zu sein, und es ist wirklich überraschend, dass dies das Standardverhalten ist, wenn es so unintuitiv ist. Offensichtlich ist der Browser so ausgestattet, dass er weiß, dass das innere Bildlauf-Div an seiner Grenze ist, um das Ereignis stattdessen auf das Fenster anwenden zu können. Warum stehen also keine Handles zum Abfragen zur Verfügung?
Robisrob
8

Sie könnten ein Mouseover-Ereignis auf dem div verwenden, um die Body-Bildlaufleiste zu deaktivieren, und dann ein Mouseout-Ereignis, um sie erneut zu aktivieren?

ZB das HTML

<div onmouseover="disableBodyScroll();" onmouseout="enableBodyScroll();">
    content
</div>

Und dann gefällt das Javascript so:

var body = document.getElementsByTagName('body')[0];
function disableBodyScroll() {
    body.style.overflowY = 'hidden';
}
function enableBodyScroll() {
    body.style.overflowY = 'auto';
}
joe92
quelle
12
Sie können document.bodystattdessen auch verwenden.
Ry-
8

Hier ist eine browserübergreifende Methode, um dies auf der Y-Achse zu tun. Sie funktioniert auf Desktop- und Mobilgeräten. Getestet unter OSX und iOS.

var scrollArea = this.querySelector(".scroll-area");
scrollArea.addEventListener("wheel", function() {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var deltaY = event.deltaY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
}, {passive:false});

scrollArea.addEventListener("touchstart", function(event) {
    this.previousClientY = event.touches[0].clientY;
}, {passive:false});

scrollArea.addEventListener("touchmove", function(event) {
    var scrollTop = this.scrollTop;
    var maxScroll = this.scrollHeight - this.offsetHeight;
    var currentClientY = event.touches[0].clientY;
    var deltaY = this.previousClientY - currentClientY;
    if ( (scrollTop >= maxScroll && deltaY > 0) || (scrollTop === 0 && deltaY < 0) ) {
        event.preventDefault();
    }
    this.previousClientY = currentClientY;
}, {passive:false});
Patrick Matte
quelle
Das funktioniert super! Wow, genau das, wonach ich gesucht habe. Es braucht definitiv mehr Upvotes.
delato468
Diese Lösung funktioniert ziemlich gut , aber braucht ein wenig anpassen: Notwendigkeit der Änderungen scrollTop === maxScroll durch scrollTop >= maxScroll. Es scheint seltsam zu sein, in einem Fall wurde es benötigt
tchiot.ludo
7

Ich habe eine Lösung für dieses Problem geschrieben

  var div;
  div = document.getElementsByClassName('selector')[0];

  div.addEventListener('mousewheel', function(e) {
    if (div.clientHeight + div.scrollTop + e.deltaY >= div.scrollHeight) {
      e.preventDefault();
      div.scrollTop = div.scrollHeight;
    } else if (div.scrollTop + e.deltaY <= 0) {
      e.preventDefault();
      div.scrollTop = 0;
    }
  }, false);
Alex Golovin
quelle
Eine der wenigen Lösungen hier, die funktioniert, ohne dass die Seitenelemente aufgrund des eingestellten Überlaufs störend springen.
Skeptiker
+1 Dies ist eine feste Lösung. Wenn Sie dies an einen scrollbaren Container anhängen, soll div in diesem Beispiel sein e.currentTarget.
Matt
sehr saubere Lösung. Vielen Dank
Thinh Bui
Hat in Chrome 61.0.3163.100 und Safari 11.0 funktioniert, aber nicht in FireFox 56.0 (Mac OS El Capitan)
BigJ
Dies ist die beste native Lösung. Muss falsejedoch nicht angegeben werden, addEventListenerda dies die Standardeinstellung ist. Darüber hinaus sollten die Vergleiche einfache Ungleichungen ( >und <) sein, nicht >=oder <=.
Quolonel Fragen
6

Wenn ich Ihre Frage richtig verstehe, möchten Sie verhindern, dass der Hauptinhalt gescrollt wird, wenn sich die Maus über einem Div befindet (sagen wir eine Seitenleiste). Aus diesem Grund ist die Seitenleiste möglicherweise kein untergeordnetes Element des Bildlaufcontainers des Hauptinhalts (der das Browserfenster war), um zu verhindern, dass das Bildlaufereignis zu seinem übergeordneten Element sprudelt.

Dies erfordert möglicherweise einige Markup-Änderungen auf folgende Weise:

<div id="wrapper"> 
    <div id="content"> 
    </div> 
</div> 
<div id="sidebar"> 
</div> 

Sehen Sie, dass es in dieser Beispielgeige funktioniert, und vergleichen Sie dies mit dieser Beispielgeige, die ein etwas anderes Mausverlaufsverhalten der Seitenleiste aufweist.

Siehe auch nur einen bestimmten Div mit der Hauptscrollleiste des Browsers scrollen .

NGLN
quelle
In diesem Fall befindet sich die Seitenleiste außerhalb des Wrapper-Div. Ich glaube also nicht, dass die Schriftrolle zum Elternteil sprudelt
Jeevan
Mit "diesem Fall" meinen Sie Ihren Fall? Wenn nicht: Sie sind genau richtig. Wenn ja: Wenn Ihre Seite am Ende des Div-Bildlaufs gescrollt wird, sprudelt die Bildlaufnachricht zum Div-Elternteil. Ich denke, Ihre Seite und Div sind keine Geschwister, sondern Eltern und Kind.
NGLN
Ja, Page ist das übergeordnete Element meines Div. Wenn das Ende erreicht ist, wird die Seite gescrollt, was ich nicht möchte.
Jeevan
Wenn Sie Ihr div nicht zu einem Geschwister des Hauptinhalts machen können, kann dieses Problem nicht allein mit HTML + CSS behoben werden. Dies ist das Standardverhalten.
NGLN
1
Ich denke, dies ist die effizienteste Lösung aller bereitgestellten Antworten. Mit einem guten sauberen Markup am unteren Rand einer Seite sind weit weniger CSS- und JS-Hacks erforderlich, um das gewünschte Verhalten zu erzielen.
6

Wie hier beantwortet , unterstützen die meisten modernen Browser jetzt die overscroll-behavior: none;CSS-Eigenschaft, die eine Bildlaufverkettung verhindert. Und das war's, nur eine Zeile!

Andriy Stolyar
quelle
2
Dies sollte die richtige Antwort im Jahr 2020 sein. Für meinen Anwendungsfall war die beste Lösung overscroll-behavior: contain;.
Pier
3

Dadurch wird das Scrollen im Fenster deaktiviert, wenn Sie das Auswahlelement eingeben. funktioniert wie Zauber.

elements = $(".selector");

elements.on('mouseenter', function() {
    window.currentScrollTop = $(window).scrollTop();
    window.currentScrollLeft = $(window).scrollTop();
    $(window).on("scroll.prevent", function() {
        $(window).scrollTop(window.currentScrollTop);
        $(window).scrollLeft(window.currentScrollLeft);
    });
});

elements.on('mouseleave', function() {
    $(window).off("scroll.prevent");
});
ceed
quelle
Dies ist in der Tat eine funktionierende Lösung. Ich brauchte es in reinem js, also habe ich es neu geschrieben. Wenn jemand es braucht, ist es hier . Für alle, die noch nach der Lösung suchen, sollten Sie meine Antwort unten lesen .
Andriy Stolyar
2

Sie können das Scrollen der gesamten Seite inaktivieren, indem Sie so etwas tun, aber die Bildlaufleiste anzeigen!

<div onmouseover="document.body.style.overflow='hidden'; document.body.style.position='fixed';" onmouseout="document.body.style.overflow='auto'; document.body.style.position='relative';"></div>
joseantgv
quelle
2
$this.find('.scrollingDiv').on('mousewheel DOMMouseScroll', function (e) {
  var delta = -e.originalEvent.wheelDelta || e.originalEvent.detail;
  var scrollTop = this.scrollTop;
  if((delta < 0 && scrollTop === 0) || (delta > 0 && this.scrollHeight - this.clientHeight - scrollTop === 0)) {
    e.preventDefault();
  }
});
Neil Taylor
quelle
1

Basierend auf der Antwort von ceed ist hier eine Version, die das Verschachteln von scrollgeschützten Elementen ermöglicht. Nur das Element, über dem sich die Maus befindet, wird gescrollt, und es wird ganz reibungslos gescrollt. Diese Version ist ebenfalls wieder verfügbar. Es kann mehrfach für dasselbe Element verwendet werden und entfernt und behandelt die Handler korrekt.

jQuery.fn.scrollGuard = function() {
    this
        .addClass('scroll-guarding')
        .off('.scrollGuard').on('mouseenter.scrollGuard', function() {
            var $g = $(this).parent().closest('.scroll-guarding');
            $g = $g.length ? $g : $(window);
            $g[0].myCst = $g.scrollTop();
            $g[0].myCsl = $g.scrollLeft();
            $g.off("scroll.prevent").on("scroll.prevent", function() {
                $g.scrollTop($g[0].myCst);
                $g.scrollLeft($g[0].myCsl);
            });
        })
        .on('mouseleave.scrollGuard', function() {
            var $g = $(this).parent().closest('.scroll-guarding');
            $g = $g.length ? $g : $(window);
            $g.off("scroll.prevent");
        });
};

Eine einfache Möglichkeit besteht darin scroll-guard, allen Elementen auf der Seite, auf denen Sie einen Bildlauf durchführen können , eine Klasse hinzuzufügen, z . Dann verwenden Sie $('.scroll-guard').scrollGuard(), um sie zu schützen.

d'Artagnan Immergrüne Barbosa
quelle
0

Wenn Sie einen overflow: hiddenStil anwenden , sollte er verschwinden

edit: eigentlich habe ich deine frage falsch gelesen, das wird nur die scrollleiste verbergen, aber ich glaube nicht, dass du danach suchst.

JavaKungFu
quelle
1
Ich brauche beide die Bildlaufleiste. Ich spreche über das Verhalten. Wenn ich mit meinem Maus-Trackball am Ende des Div-Scrolls scrolle, darf nicht die ganze Seite gescrollt werden.
Jeevan
0

Ich konnte keine der Antworten für die Arbeit in Chrome und Firefox erhalten, daher habe ich mir diese Zusammenführung ausgedacht:

$someElement.on('mousewheel DOMMouseScroll', scrollProtection);

function scrollProtection(event) {
    var $this = $(this);
    event = event.originalEvent;
    var direction = (event.wheelDelta * -1) || (event.detail);
    if (direction < 0) {
        if ($this.scrollTop() <= 0) {
            return false;
        }
    } else {
        if ($this.scrollTop() + $this.innerHeight() >= $this[0].scrollHeight) {
            return false;
        }
    }
}
d.breve
quelle