Impedire lo scorrimento dell’elemento genitore quando la posizione di scorrimento dell’elemento interno raggiunge l’alto / il basso?

Ho una piccola “cassetta degli attrezzi mobile” – un div con position:fixed; overflow:auto position:fixed; overflow:auto . Funziona bene.

Ma quando si scorre all’interno di quella casella (con la rotellina del mouse) e si raggiunge la parte inferiore o superiore, l’elemento padre “assume” la “richiesta di scorrimento”: il documento dietro la casella degli strumenti scorre.
– Che è fastidioso e non quello che l’utente “ha chiesto”.

Sto usando jQuery e ho pensato di poter fermare questo comportamento con event.stoppropagation ():
$("#toolBox").scroll( function(event){ event.stoppropagation() });

Entra nella funzione, ma comunque, la propagazione avviene comunque (il documento scorre)
– È sorprendentemente difficile cercare questo argomento su SO (e Google), quindi devo chiedere:
Come impedire la propagazione / gorgogliamento dell’evento di scorrimento?

Modificare:
Soluzione di lavoro grazie a amustill (e Brandon Aaron per il plugin mousewheel qui:
https://github.com/brandonaaron/jquery-mousewheel/raw/master/jquery.mousewheel.js

 $(".ToolPage").bind('mousewheel', function(e, d) var t = $(this); if (d > 0 && t.scrollTop() === 0) { e.preventDefault(); } else { if (d < 0 && (t.scrollTop() == t.get(0).scrollHeight - t.innerHeight())) { e.preventDefault(); } } }); 

È ansible con l’uso del plug-in Mousewheel di Brandon Aaron.

Ecco una demo: http://jsbin.com/jivutakama/edit?html,js,output

Sto aggiungendo questa risposta per completezza perché la risposta accettata da @amustill non risolve correttamente il problema in Internet Explorer . Si prega di vedere i commenti nel mio post originale per i dettagli. Inoltre, questa soluzione non richiede alcun plugin – solo jQuery.

In sostanza, il codice funziona gestendo l’evento mousewheel . Ognuno di questi eventi contiene una wheelDelta uguale al numero di px cui si muoverà l’area scorrevole. Se questo valore è >0 , allora stiamo scorrendo up . Se wheelDelta è <0 allora stiamo scorrendo down .

FireFox : FireFox utilizza DOMMouseScroll come evento e popola originalEvent.detail , il cui +/- è invertito rispetto a quanto descritto sopra. Generalmente restituisce intervalli di 3 , mentre altri browser tornano a scorrere a intervalli di 120 (almeno sulla mia macchina). Per correggere, lo rileviamo e moltiplichiamo per -40 per normalizzare.

@ La risposta di amustill funziona cancellando l'evento se l'area scorrevole di

è già nella posizione massima o inferiore. Tuttavia, Internet Explorer ignora l'evento annullato in situazioni in cui il delta è maggiore dello spazio scorrevole rimanente.

In altre parole, se hai un

200px altezza contenente 500px di contenuto scorrevole, e lo scrollTop corrente è 400 , un evento della mousewheel che indica al browser di scorrere 120px ulteriormente comporterà sia il

che il scorrimento, perché 400 + 120 > 500 .

Quindi, per risolvere il problema, dobbiamo fare qualcosa di leggermente diverso, come mostrato di seguito:

Il codice jQuery richiesto è:

 $(document).on('DOMMouseScroll mousewheel', '.Scrollable', function(ev) { var $this = $(this), scrollTop = this.scrollTop, scrollHeight = this.scrollHeight, height = $this.innerHeight(), delta = (ev.type == 'DOMMouseScroll' ? ev.originalEvent.detail * -40 : ev.originalEvent.wheelDelta), up = delta > 0; var prevent = function() { ev.stopPropagation(); ev.preventDefault(); ev.returnValue = false; return false; } if (!up && -delta > scrollHeight - height - scrollTop) { // Scrolling down, but this will take us past the bottom. $this.scrollTop(scrollHeight); return prevent(); } else if (up && delta > scrollTop) { // Scrolling up, but this will take us past the top. $this.scrollTop(0); return prevent(); } }); 

In sostanza, questo codice annulla qualsiasi evento di scorrimento che creerebbe la condizione di bordo indesiderato, quindi utilizza jQuery per impostare lo scrollTop di

sul valore massimo o minimo, a seconda della direzione in cui l'evento della mousewheel stava richiedendo.

Poiché l'evento viene annullato interamente in entrambi i casi, non si diffonde mai nel body e pertanto risolve il problema in IE, nonché in tutti gli altri browser.

Ho anche presentato un esempio funzionante su jsFiddle .

So che è una domanda piuttosto vecchia, ma dal momento che questo è uno dei migliori risultati in google … ho dovuto in qualche modo annullare lo scroll bubbling senza jQuery e questo codice funziona per me:

 function preventDefault(e) { e = e || window.event; if (e.preventDefault) e.preventDefault(); e.returnValue = false; } document.getElementById('a').onmousewheel = function(e) { document.getElementById('a').scrollTop -= e. wheelDeltaY; preventDefault(e); } 

EDIT: esempio CodePen

Per AngularJS, ho definito la seguente direttiva:

 module.directive('isolateScrolling', function () { return { restrict: 'A', link: function (scope, element, attr) { element.bind('DOMMouseScroll', function (e) { if (e.detail > 0 && this.clientHeight + this.scrollTop == this.scrollHeight) { this.scrollTop = this.scrollHeight - this.clientHeight; e.stopPropagation(); e.preventDefault(); return false; } else if (e.detail < 0 && this.scrollTop <= 0) { this.scrollTop = 0; e.stopPropagation(); e.preventDefault(); return false; } }); element.bind('mousewheel', function (e) { if (e.deltaY > 0 && this.clientHeight + this.scrollTop >= this.scrollHeight) { this.scrollTop = this.scrollHeight - this.clientHeight; e.stopPropagation(); e.preventDefault(); return false; } else if (e.deltaY < 0 && this.scrollTop <= 0) { this.scrollTop = 0; e.stopPropagation(); e.preventDefault(); return false; } return true; }); } }; }); 

E poi aggiunto all'elemento scorrevole (il menu a tendina ul):

  

Testato su Chrome e Firefox. Lo scorrimento fluido di Chrome sconfigge questo hack quando un grande movimento della rotellina del mouse viene effettuato vicino (ma non a) nella parte superiore o inferiore della regione di scorrimento.

Ci sono tonnellate di domande come questa là fuori, con molte risposte, ma non sono riuscito a trovare una soluzione soddisfacente che non includesse eventi, script, plug-in, ecc. Volevo tenerlo dritto in HTML e CSS. Alla fine ho trovato una soluzione che funzionava, anche se comportava la ristrutturazione del markup per rompere la catena di eventi.


1. Problema di base

L’input di scorrimento (cioè: la rotellina del mouse) applicato all’elemento modale si riverserà in un elemento antenato e lo scorrerà nella stessa direzione, se alcuni di questi elementi sono scorrevoli:

(Tutti gli esempi sono pensati per essere visualizzati su risoluzioni desktop)

https://jsfiddle.net/ybkbg26c/5/

HTML:

 

CSS:

 #modal { position: absolute; height: 100px; width: 100px; top: 20%; left: 20%; overflow-y: scroll; } #parent { height: 4000px; } 

2. Nessuna scroll genitore sullo scroll modale

Il motivo per cui l’antenato finisce lo scorrimento è perché l’evento di scorrimento bolle e qualche elemento della catena è in grado di gestirlo. Un modo per fermarlo è assicurarsi che nessuno degli elementi della catena sappia come gestire la pergamena. Nei termini del nostro esempio, possiamo refactoring dell’albero per spostare il modale fuori dall’elemento genitore. Per motivi oscuri, non è sufficiente mantenere i genitori DOM modali e i genitori; il genitore deve essere avvolto da un altro elemento che stabilisce un nuovo contesto di impilamento. Un involucro assolutamente posizionato attorno al genitore può fare il trucco.

Il risultato che otteniamo è che fino a quando la modale riceve l’evento di scorrimento, l’evento non si bolla con l’elemento “genitore”.

In genere dovrebbe essere ansible riprogettare l’albero DOM per supportare questo comportamento senza influire su ciò che l’utente vede.

https://jsfiddle.net/0bqq31Lv/3/

HTML:

 

CSS (solo nuovi):

 #context { position: absolute; overflow-y: scroll; top: 0; bottom: 0; left: 0; right: 0; } 

3. Non scorrere ovunque tranne che nel modale mentre è attivo

La soluzione sopra ancora consente al genitore di ricevere eventi di scorrimento, purché non siano intercettati dalla finestra modale (cioè se triggersta dalla rotellina del mouse mentre il cursore non si trova sopra il modale). Questo a volte è indesiderabile e potremmo voler proibire tutto lo scorrimento dello sfondo mentre la modale è triggers. Per fare ciò, abbiamo bisogno di inserire un ulteriore contesto di stacking che si estenda all’intera finestra dietro il modal. Possiamo farlo visualizzando un overlay assolutamente posizionato, che può essere completamente trasparente se necessario (ma non visibility:hidden ).

https://jsfiddle.net/0bqq31Lv/2/

HTML:

 

CSS (nuovo sopra 2):

 #overlay { background-color: transparent; position: absolute; top: 0; bottom: 0; left: 0; right: 0; } 

Direttiva JS angular

Ho dovuto avvolgere una direttiva angular. Quello che segue è un Mashup delle altre risposte qui. testato su Chrome e Internet Explorer 11.

 var app = angular.module('myApp'); app.directive("preventParentScroll", function () { return { restrict: "A", scope: false, link: function (scope, elm, attr) { elm.bind('mousewheel', onMouseWheel); function onMouseWheel(e) { elm[0].scrollTop -= (e.wheelDeltaY || (e.originalEvent && (e.originalEvent.wheelDeltaY || e.originalEvent.wheelDelta)) || e.wheelDelta || 0); e.stopPropagation(); e.preventDefault(); e.returnValue = false; } } } }); 

uso

 
...

Spero che questo aiuti la prossima persona che arriva da una ricerca su Google.

Come variante, per evitare problemi di prestazioni con la scroll o la gestione della mousewheel , è ansible utilizzare il codice come di seguito:

css:

 body.noscroll { overflow: hidden; } .scrollable { max-height: 200px; overflow-y: scroll; border: 1px solid #ccc; } 

html:

 
...A bunch of items to make the div scroll...
...A bunch of text to make the body scroll...

js:

 var $document = $(document), $body = $('body'), $scrolable = $('.scrollable'); $scrolable.on({ 'mouseenter': function () { // add hack class to prevent workspace scroll when scroll outside $body.addClass('noscroll'); }, 'mouseleave': function () { // remove hack class to allow scroll $body.removeClass('noscroll'); } }); 

Esempio di lavoro: http://jsbin.com/damuwinarata/4

Usando le proprietà di scorrimento degli elementi nativi con il valore delta dal plugin mousewheel:

 $elem.on('mousewheel', function (e, delta) { // Restricts mouse scrolling to the scrolling range of this element. if ( this.scrollTop < 1 && delta > 0 || (this.clientHeight + this.scrollTop) === this.scrollHeight && delta < 0 ) { e.preventDefault(); } }); 

Tutte le soluzioni fornite in questo thread non menzionano un modo esistente – e nativo – per risolvere questo problema senza riordinare DOM e / o usare trucchi per prevenire eventi. Ma c’è una buona ragione: in questo modo è proprietario – e disponibile solo sulla piattaforma web MS. Citando MSDN :

-ms-scroll-chaining property – specifica il comportamento di scorrimento che si verifica quando un utente raggiunge il limite di scroll durante una manipolazione. Valori di proprietà:

incatenato – Valore iniziale. L’elemento genitore scorrevole più vicino inizia a scorrere quando l’utente raggiunge un limite di scorrimento durante una manipolazione. Non viene mostrato alcun effetto di rimbalzo.

none – Un effetto di rimbalzo viene mostrato quando l’utente raggiunge un limite di scroll durante una manipolazione.

Certo, questa proprietà è supportata solo su IE10 + / Edge. Tuttavia, ecco una citazione interessante :

Per darti un’idea di quanto possa essere popolare prevenire il concatenamento di scroll, secondo la mia ricerca rapida su http-archive “-ms-scroll-chaining: none” è usato nello 0,4% delle prime 300 pagine, nonostante sia limitato nelle funzionalità e supportato solo su IE / Edge.

E ora buone notizie, tutti! A partire da Chrome 63, abbiamo finalmente anche una cura nativa per le piattaforms basate su Blink – che è sia Chrome (ovviamente) che Android WebView (presto).

Citando l’articolo introduttivo :

La proprietà del comportamento overscroll è una nuova funzionalità CSS che controlla il comportamento di ciò che accade quando si scorre un container in eccesso (inclusa la pagina stessa). Puoi usarlo per annullare il concatenamento dello scroll, disabilitare / personalizzare l’azione pull-to-refresh, disabilitare gli effetti rubberbanding su iOS (quando Safari implementa il comportamento overscroll), e altro ancora. […]

La proprietà accetta tre valori possibili:

auto – Predefinito. Le pergamene che hanno origine sull’elemento possono propagarsi agli elementi degli antenati.

contiene – impedisce il concatenamento dello scorrimento. Le pergamene non si propagano agli antenati ma vengono mostrati gli effetti locali all’interno del nodo. Ad esempio, l’effetto glow overscroll su Android o l’effetto rubberbanding su iOS che avvisa l’utente quando ha raggiunto un limite di scorrimento. Nota: utilizzando il comportamento overscroll: contiene sull’elemento html previene le azioni di navigazione overscroll.

nessuno – lo stesso che contiene ma previene anche gli effetti di overscroll all’interno del nodo stesso (ad es. bagliore overscroll Android o rubberbanding iOS).

[…] La parte migliore è che l’utilizzo del comportamento overscroll non influisce negativamente sulle prestazioni della pagina come gli hack menzionati nell’introduzione!

Ecco questa funzionalità in azione . Ed ecco il corrispondente documento del modulo CSS .

AGGIORNAMENTO: Firefox, dalla versione 59, è entrato nel club, e MS Edge dovrebbe implementare questa funzione nella versione 18. Ecco i caniusage corrispondenti.

Nel caso qualcuno stia ancora cercando una soluzione per questo, il seguente plugin fa il lavoro http://mohammadyounes.github.io/jquery-scrollLock/

Affronta completamente il problema del blocco della rotellina del mouse all’interno di un determinato contenitore, impedendone la propagazione all’elemento padre.

Non cambia la velocità di scorrimento della rotella, l’esperienza dell’utente non sarà influenzata. e si ottiene lo stesso comportamento indipendentemente dalla velocità di scorrimento verticale della rotellina del mouse del sistema operativo (Su Windows può essere impostata su uno schermo o su una riga fino a 100 linee per tacca).

Demo: http://mohammadyounes.github.io/jquery-scrollLock/example/

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

Ecco una semplice versione JavaScript:

 function scroll(e) { var delta = (e.type === "mousewheel") ? e.wheelDelta : e.detail * -40; if (delta < 0 && (this.scrollHeight - this.offsetHeight - this.scrollTop) <= 0) { this.scrollTop = this.scrollHeight; e.preventDefault(); } else if (delta > 0 && delta > this.scrollTop) { this.scrollTop = 0; e.preventDefault(); } } document.querySelectorAll(".scroller").addEventListener("mousewheel", scroll); document.querySelectorAll(".scroller").addEventListener("DOMMouseScroll", scroll); 

la risposta di amustill come un knockout handler:

 ko.bindingHandlers.preventParentScroll = { init: function (element, valueAccessor, allBindingsAccessor, context) { $(element).mousewheel(function (e, d) { var t = $(this); if (d > 0 && t.scrollTop() === 0) { e.preventDefault(); } else { if (d < 0 && (t.scrollTop() == t.get(0).scrollHeight - t.innerHeight())) { e.preventDefault(); } } }); } }; 

Questo in realtà funziona in AngularJS. Testato su Chrome e Firefox.

 .directive('stopScroll', function () { return { restrict: 'A', link: function (scope, element, attr) { element.bind('mousewheel', function (e) { var $this = $(this), scrollTop = this.scrollTop, scrollHeight = this.scrollHeight, height = $this.height(), delta = (e.type == 'DOMMouseScroll' ? e.originalEvent.detail * -40 : e.originalEvent.wheelDelta), up = delta > 0; var prevent = function() { e.stopPropagation(); e.preventDefault(); e.returnValue = false; return false; }; if (!up && -delta > scrollHeight - height - scrollTop) { // Scrolling down, but this will take us past the bottom. $this.scrollTop(scrollHeight); return prevent(); } else if (up && delta > scrollTop) { // Scrolling up, but this will take us past the top. $this.scrollTop(0); return prevent(); } }); } }; }) 

il metodo sopra non è così naturale, dopo un po ‘su Google trovo una soluzione più bella e non ho bisogno di jQuery. vedi [1] e demo [2].

  var element = document.getElementById('uf-notice-ul'); var isMacWebkit = (navigator.userAgent.indexOf("Macintosh") !== -1 && navigator.userAgent.indexOf("WebKit") !== -1); var isFirefox = (navigator.userAgent.indexOf("firefox") !== -1); element.onwheel = wheelHandler; // Future browsers element.onmousewheel = wheelHandler; // Most current browsers if (isFirefox) { element.scrollTop = 0; element.addEventListener("DOMMouseScroll", wheelHandler, false); } // prevent from scrolling parrent elements function wheelHandler(event) { var e = event || window.event; // Standard or IE event object // Extract the amount of rotation from the event object, looking // for properties of a wheel event object, a mousewheel event object // (in both its 2D and 1D forms), and the Firefox DOMMouseScroll event. // Scale the deltas so that one "click" toward the screen is 30 pixels. // If future browsers fire both "wheel" and "mousewheel" for the same // event, we'll end up double-counting it here. Hopefully, however, // cancelling the wheel event will prevent generation of mousewheel. var deltaX = e.deltaX * -30 || // wheel event e.wheelDeltaX / 4 || // mousewheel 0; // property not defined var deltaY = e.deltaY * -30 || // wheel event e.wheelDeltaY / 4 || // mousewheel event in Webkit (e.wheelDeltaY === undefined && // if there is no 2D property then e.wheelDelta / 4) || // use the 1D wheel property e.detail * -10 || // Firefox DOMMouseScroll event 0; // property not defined // Most browsers generate one event with delta 120 per mousewheel click. // On Macs, however, the mousewheels seem to be velocity-sensitive and // the delta values are often larger multiples of 120, at // least with the Apple Mouse. Use browser-testing to defeat this. if (isMacWebkit) { deltaX /= 30; deltaY /= 30; } e.currentTarget.scrollTop -= deltaY; // If we ever get a mousewheel or wheel event in (a future version of) // Firefox, then we don't need DOMMouseScroll anymore. if (isFirefox && e.type !== "DOMMouseScroll") { element.removeEventListener("DOMMouseScroll", wheelHandler, false); } // Don't let this event bubble. Prevent any default action. // This stops the browser from using the mousewheel event to scroll // the document. Hopefully calling preventDefault() on a wheel event // will also prevent the generation of a mousewheel event for the // same rotation. if (e.preventDefault) e.preventDefault(); if (e.stopPropagation) e.stopPropagation(); e.cancelBubble = true; // IE events e.returnValue = false; // IE events return false; } 

Per chi usa MooTools, ecco il codice equivalente:

  'mousewheel': function(event){ var height = this.getSize().y; height -= 2; // Not sure why I need this bodge if ((this.scrollTop === (this.scrollHeight - height) && event.wheel < 0) || (this.scrollTop === 0 && event.wheel > 0)) { event.preventDefault(); } 

Ricorda che io, come altri, ho dovuto modificare un valore di un paio di px, cioè l’altezza – = 2 è per.

Fondamentalmente la differenza principale è che in MooTools, le informazioni delta provengono da event.wheel invece di un parametro extra passato all’evento.

Inoltre, ho avuto problemi se ho associato questo codice a qualsiasi cosa (event.target.scrollHeight per una funzione associata non equivale a this.scrollHeight per uno non vincolato)

Spero che questo aiuti qualcuno tanto quanto questo post mi ha aiutato;)

il mio plugin jQuery:

 $('.child').dontScrollParent(); $.fn.dontScrollParent = function() { this.bind('mousewheel DOMMouseScroll',function(e) { var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail; if (delta > 0 && $(this).scrollTop() <= 0) return false; if (delta < 0 && $(this).scrollTop() >= this.scrollHeight - $(this).height()) return false; return true; }); } 

Nuovo web dev qui. Questo ha funzionato come un fascino per me sia su IE che su Chrome.

 static preventScrollPropagation(e: HTMLElement) { e.onmousewheel = (ev) => { var preventScroll = false; var isScrollingDown = ev.wheelDelta < 0; if (isScrollingDown) { var isAtBottom = e.scrollTop + e.clientHeight == e.scrollHeight; if (isAtBottom) { preventScroll = true; } } else { var isAtTop = e.scrollTop == 0; if (isAtTop) { preventScroll = true; } } if (preventScroll) { ev.preventDefault(); } } } 

Non lasciatevi ingannare dal numero di linee, è piuttosto semplice - solo un po 'prolisso per la leggibilità (codice di auto-documentazione ftw giusto?)

Inoltre dovrei menzionare che il linguaggio qui è TypeScript , ma come sempre, è semplice convertirlo in JS.

Ho pensato questo dalla libreria scelta: https://github.com/harvesthq/chosen/blob/master/coffee/chosen.jquery.coffee

 function preventParentScroll(evt) { var delta = evt.deltaY || -evt.wheelDelta || (evt && evt.detail) if (delta) { evt.preventDefault() if (evt.type == 'DOMMouseScroll') { delta = delta * 40 } fakeTable.scrollTop = delta + fakeTable.scrollTop } } var el = document.getElementById('some-id') el.addEventListener('mousewheel', preventParentScroll) el.addEventListener('DOMMouseScroll', preventParentScroll) 

Questo funziona per me.

Odio i post necro ma stavo cercando questo per MooTools e questo è stato il primo che è venuto fuori. L’esempio originale di MooTools funzionerebbe con lo scorrimento verso l’alto, ma non lo scorrimento verso il basso, quindi ho deciso di scriverlo.


 var stopScroll = function (e) { var scrollTo = null; if (e.event.type === 'mousewheel') { scrollTo = (e.event.wheelDelta * -1); } else if (e.event.type === 'DOMMouseScroll') { scrollTo = 40 * e.event.detail; } if (scrollTo) { e.preventDefault(); this.scrollTo(0, scrollTo + this.scrollTop); } return false; }; 

Uso:

 (function)($){ window.addEvent('domready', function(){ $$('.scrollable').addEvents({ 'mousewheel': stopScroll, 'DOMMouseScroll': stopScroll }); }); })(document.id); 

Plugin jQuery con emulare lo scrolling naturale per Internet Explorer

  $.fn.mousewheelStopPropagation = function(options) { options = $.extend({ // defaults wheelstop: null // Function }, options); // Compatibilities var isMsIE = ('Microsoft Internet Explorer' === navigator.appName); var docElt = document.documentElement, mousewheelEventName = 'mousewheel'; if('onmousewheel' in docElt) { mousewheelEventName = 'mousewheel'; } else if('onwheel' in docElt) { mousewheelEventName = 'wheel'; } else if('DOMMouseScroll' in docElt) { mousewheelEventName = 'DOMMouseScroll'; } if(!mousewheelEventName) { return this; } function mousewheelPrevent(event) { event.preventDefault(); event.stopPropagation(); if('function' === typeof options.wheelstop) { options.wheelstop(event); } } return this.each(function() { var _this = this, $this = $(_this); $this.on(mousewheelEventName, function(event) { var origiEvent = event.originalEvent; var scrollTop = _this.scrollTop, scrollMax = _this.scrollHeight - $this.outerHeight(), delta = -origiEvent.wheelDelta; if(isNaN(delta)) { delta = origiEvent.deltaY; } var scrollUp = delta < 0; if((scrollUp && scrollTop <= 0) || (!scrollUp && scrollTop >= scrollMax)) { mousewheelPrevent(event); } else if(isMsIE) { // Fix Internet Explorer and emulate natural scrolling var animOpt = { duration:200, easing:'linear' }; if(scrollUp && -delta > scrollTop) { $this.stop(true).animate({ scrollTop:0 }, animOpt); mousewheelPrevent(event); } else if(!scrollUp && delta > scrollMax - scrollTop) { $this.stop(true).animate({ scrollTop:scrollMax }, animOpt); mousewheelPrevent(event); } } }); }); }; 

https://github.com/basselin/jquery-mousewheel-stop-propagation/blob/master/mousewheelStopPropagation.js

La soluzione migliore che ho trovato è stata ascoltare l’evento scroll sulla finestra e impostare la scrollTop sulla precedente scrollTop se il div child era visibile.

 prevScrollPos = 0 $(window).scroll (ev) -> if $('#mydiv').is(':visible') document.body.scrollTop = prevScrollPos else prevScrollPos = document.body.scrollTop 

There is a flicker in the background of the child div if you fire a lot of scroll events, so this could be tweaked, but it is hardly noticed and it was sufficient for my use case.

I have a similar situation and here’s how i solved it:
All my scrollable elements get the class scrollable .

 $(document).on('wheel', '.scrollable', function(evt) { var offsetTop = this.scrollTop + parseInt(evt.originalEvent.deltaY, 10); var offsetBottom = this.scrollHeight - this.getBoundingClientRect().height - offsetTop; if (offsetTop < 0 || offsetBottom < 0) { evt.preventDefault(); } else { evt.stopImmediatePropagation(); } }); 

stopImmediatePropagation() makes sure not to scroll parent scrollable area from scrollable child area.

Here's a vanilla JS implementation of it: http://jsbin.com/lugim/2/edit?js,output

Don’t use overflow: hidden; on body . It automatically scrolls everything to the top. There’s no need for JavaScript either. Make use of overflow: auto; :

HTML Structure

 
lengthy content here

Styling

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

Play with the demo here .

Check out Leland Kwong’s code.

Basic idea is to bind the wheeling event to the child element, and then use the native javascript property scrollHeight and the jquery property outerHeight of the child element to detect the end of the scroll, upon which return false to the wheeling event to prevent any scrolling.

 var scrollableDist,curScrollPos,wheelEvent,dY; $('#child-element').on('wheel', function(e){ scrollableDist = $(this)[0].scrollHeight - $(this).outerHeight(); curScrollPos = $(this).scrollTop(); wheelEvent = e.originalEvent; dY = wheelEvent.deltaY; if ((dY>0 && curScrollPos >= scrollableDist) || (dY<0 && curScrollPos <= 0)) { return false; } }); 

There’s also a funny trick to lock the parent’s scrollTop when mouse hovers over a scrollable element. This way you don’t have to implement your own wheel scrolling.

Here’s an example for preventing document scroll, but it can be adjusted for any element.

 scrollable.mouseenter(function () { var scroll = $(document).scrollTop(); $(document).on('scroll.trap', function () { if ($(document).scrollTop() != scroll) $(document).scrollTop(scroll); }); }); scrollable.mouseleave(function () { $(document).off('scroll.trap'); }); 

MK offered a great plugin in his answer. Plugin can be found here . However, for the sake of completion, I thought it’d be a good idea to put it together in one answer for AngularJS.

  1. Start by injecting the bower or npm (whichever is preferred)

     bower install jquery-scrollLock --save npm install jquery-scroll-lock --save 
  2. Add the following directive. I am choosing to add it as an attribute

     (function() { 'use strict'; angular .module('app') .directive('isolateScrolling', isolateScrolling); function isolateScrolling() { return { restrict: 'A', link: function(sc, elem, attrs) { $('.scroll-container').scrollLock(); } } } })(); 
  3. And the important piece the plugin fails to document in their website is the HTML structure that it must follow.

     
    ... whatever ...

The attribute isolate-scrolling must contain the scrollable class and it all needs to be inside the scroll-container class or whatever class you choose and the locked class must be cascaded.

It is worth to mention that with modern frameworks like reactJS, AngularJS, VueJS, etc, there are easy solutions for this problem, when dealing with fixed position elements. Examples are side panels or overlaid elements.

The technique is called a “Portal”, which means that one of the components used in the app, without the need to actually extract it from where you are using it, will mount its children at the bottom of the body element, outside of the parent you are trying to avoid scrolling.

Note that it will not avoid scrolling the body element itself. You can combine this technique and mounting your app in a scrolling div to achieve the expected result.

Example Portal implementation in React’s material-ui: https://material-ui-next.com/api/portal/

Simple solution with mouseweel event:

 $('.element').bind('mousewheel', function(e, d) { console.log(this.scrollTop,this.scrollHeight,this.offsetHeight,d); if((this.scrollTop === (this.scrollHeight - this.offsetHeight) && d < 0) || (this.scrollTop === 0 && d > 0)) { e.preventDefault(); } }); 

You can try it this way:

 $('#element').on('shown', function(){ $('body').css('overflow-y', 'hidden'); $('body').css('margin-left', '-17px'); }); $('#element').on('hide', function(){ $('body').css('overflow-y', 'scroll'); $('body').css('margin-left', '0px'); });