Safari de iOS: cómo deshabilitar el desplazamiento excesivo pero permitir que los elementos de desplazamiento desplazables se desplacen normalmente.

Estoy trabajando en una aplicación web basada en iPad, y necesito evitar el sobrecrecimiento para que parezca menos una página web. Actualmente estoy usando esto para congelar la ventana gráfica y desactivar overscroll:

document.body.addEventListener('touchmove',function(e){ e.preventDefault(); }); 

Esto funciona bien para deshabilitar el desplazamiento en sentido descendente, pero mi aplicación tiene varios divs desplazables, y el código anterior les impide desplazarse .

Me estoy enfocando en iOS 5 y superior únicamente, así que evité las soluciones piratas como iScroll. En su lugar, estoy usando este CSS para mis divs desplazables:

 .scrollable { -webkit-overflow-scrolling: touch; overflow-y:auto; } 

Esto funciona sin el script de sobrescritura del documento, pero no resuelve el problema del desplazamiento del div.

Sin un plugin de jQuery, ¿hay alguna forma de utilizar el arreglo de sobredespliegue pero estoy exento de mis divs $ (‘scrollable’)?

EDITAR:

Encontré algo que es una solución decente:

  // Disable overscroll / viewport moving on everything but scrollable divs $('body').on('touchmove', function (e) { if (!$('.scrollable').has($(e.target)).length) e.preventDefault(); }); 

La ventana gráfica aún se mueve cuando te desplazas más allá del principio o el final de la div. Me gustaría encontrar una forma de desactivar eso también.

Esto resuelve el problema cuando pasas al principio o al final de la div

 var selScrollable = '.scrollable'; // Uses document because document will be topmost level in bubbling $(document).on('touchmove',function(e){ e.preventDefault(); }); // Uses body because jQuery on events are called off of the element they are // added to, so bubbling would not work if we used document instead. $('body').on('touchstart', selScrollable, function(e) { if (e.currentTarget.scrollTop === 0) { e.currentTarget.scrollTop = 1; } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) { e.currentTarget.scrollTop -= 1; } }); // Stops preventDefault from being called on document if it sees a scrollable div $('body').on('touchmove', selScrollable, function(e) { e.stopPropagation(); }); 

Tenga en cuenta que esto no funcionará si desea bloquear el desplazamiento de toda la página cuando un div no tiene desbordamiento. Para bloquear eso, use el siguiente controlador de eventos en lugar del inmediatamente anterior (adaptado de esta pregunta ):

 $('body').on('touchmove', selScrollable, function(e) { // Only block default if internal div contents are large enough to scroll // Warning: scrollHeight support is not universal. (https://stackoverflow.com/a/15033226/40352) if($(this)[0].scrollHeight > $(this).innerHeight()) { e.stopPropagation(); } }); 

El uso de la excelente respuesta de Tyler Dodge se mantuvo rezagado en mi iPad, así que agregué un código de aceleración, ahora es bastante fluido. Hay algunos saltos mínimos a veces mientras se desplaza.

 // Uses document because document will be topmost level in bubbling $(document).on('touchmove',function(e){ e.preventDefault(); }); var scrolling = false; // Uses body because jquery on events are called off of the element they are // added to, so bubbling would not work if we used document instead. $('body').on('touchstart','.scrollable',function(e) { // Only execute the below code once at a time if (!scrolling) { scrolling = true; if (e.currentTarget.scrollTop === 0) { e.currentTarget.scrollTop = 1; } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) { e.currentTarget.scrollTop -= 1; } scrolling = false; } }); // Prevents preventDefault from being called on document if it sees a scrollable div $('body').on('touchmove','.scrollable',function(e) { e.stopPropagation(); }); 

Además, al agregar las siguientes correcciones de CSS, algunos problemas técnicos de representación ( fuente ):

 .scrollable { overflow: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; } .scrollable * { -webkit-transform: translate3d(0,0,0); } 

Primero, evite las acciones predeterminadas en su documento completo como de costumbre:

 $(document).bind('touchmove', function(e){ e.preventDefault(); }); 

Luego, evite que su clase de elementos se propague al nivel del documento. Esto evita que scope la función anterior y, por lo tanto, e.preventDefault () no se inicia:

 $('.scrollable').bind('touchmove', function(e){ e.stopPropagation(); }); 

Este sistema parece ser más natural y menos intenso que calcular la clase en todos los movimientos táctiles. Utilice .on () en lugar de .bind () para elementos generados dinámicamente.

Considere también estas metatags para evitar que sucedan cosas desafortunadas al usar su div desplazable:

    

¿Puedes agregar un poco más de lógica en tu código de deshabilitación de desplazamiento para asegurarte de que el elemento objective en cuestión no es uno en el que te gustaría desplazarte? Algo como esto:

 document.body.addEventListener('touchmove',function(e){ if(!$(e.target).hasClass("scrollable")) { e.preventDefault(); } }); 

Compruebe si el elemento desplazable ya se desplazó hacia la parte superior cuando intenta desplazarse hacia arriba o hacia abajo cuando intenta desplazarse hacia abajo y luego evita que la acción predeterminada detenga el movimiento de toda la página.

 var touchStartEvent; $('.scrollable').on({ touchstart: function(e) { touchStartEvent = e; }, touchmove: function(e) { if ((e.originalEvent.pageY > touchStartEvent.originalEvent.pageY && this.scrollTop == 0) || (e.originalEvent.pageY < touchStartEvent.originalEvent.pageY && this.scrollTop + this.offsetHeight >= this.scrollHeight)) e.preventDefault(); } }); 

La mejor solución para esto es css / html: crea un div para envolver tus elementos, si aún no lo tienes, configúralo en posición fija y desbordamiento oculto. Opcional, configure la altura y el ancho al 100% si desea que ocupe toda la pantalla y nada más que toda la pantalla

 #wrapper{ height: 100%; width: 100%; position: fixed; overflow: hidden; } 
 

All

Your

Elements

Estaba buscando una manera de evitar el desplazamiento de todo el cuerpo cuando hay una ventana emergente con un área desplazable (una ventana de “carrito de compras” que tiene una vista desplazable de su carrito).

Escribí una solución mucho más elegante con un javascript mínimo para alternar la clase “noscroll” en su cuerpo cuando tiene una ventana emergente o div que desea desplazar (y no “sobredesplaza” todo el cuerpo de la página).

mientras que los navegadores de escritorio observan el desbordamiento: oculto: iOS parece ignorar eso a menos que establezca la posición como fija … lo que hace que toda la página tenga un ancho extraño, por lo que también debe establecer la posición y el ancho manualmente. usa este css:

 .noscroll { overflow: hidden; position: fixed; top: 0; left: 0; width: 100%; } 

y este jquery:

 /* fade in/out cart popup, add/remove .noscroll from body */ $('a.cart').click(function() { $('nav > ul.cart').fadeToggle(100, 'linear'); if ($('nav > ul.cart').is(":visible")) { $('body').toggleClass('noscroll'); } else { $('body').removeClass('noscroll'); } }); /* close all popup menus when you click the page... */ $('body').click(function () { $('nav > ul').fadeOut(100, 'linear'); $('body').removeClass('noscroll'); }); /* ... but prevent clicks in the popup from closing the popup */ $('nav > ul').click(function(event){ event.stopPropagation(); }); 

He trabajado un poco en el trabajo sin jquery. No es perfecto pero funciona bien (especialmente si tienes un scroll-x en un scoll-y) https://github.com/pinadesign/overscroll/

Cayó gratis para participar y mejorarlo

Esta solución no requiere que pongas una clase desplazable en todos tus divs desplazables por lo que es más general. El desplazamiento está permitido en todos los elementos que son, o son hijos de, elementos de ENTRADA contentables y desbordamiento de desplazamiento o autos.

Utilizo un selector personalizado y también guardo el resultado de la verificación en el elemento para mejorar el rendimiento. No es necesario verificar el mismo elemento todo el tiempo. Esto puede tener algunos problemas solo escritos, pero creo que compartiría.

 $.expr[':'].scrollable = function(obj) { var $el = $(obj); var tagName = $el.prop("tagName"); return (tagName !== 'BODY' && tagName !== 'HTML') && (tagName === 'INPUT' || $el.is("[contentEditable='true']") || $el.css("overflow").match(/auto|scroll/)); }; function preventBodyScroll() { function isScrollAllowed($target) { if ($target.data("isScrollAllowed") !== undefined) { return $target.data("isScrollAllowed"); } var scrollAllowed = $target.closest(":scrollable").length > 0; $target.data("isScrollAllowed",scrollAllowed); return scrollAllowed; } $('body').bind('touchmove', function (ev) { if (!isScrollAllowed($(ev.target))) { ev.preventDefault(); } }); } 

Si bien la inhabilitación de todos los eventos “touchmove” puede parecer una buena idea, tan pronto como necesite otros elementos desplazables en la página, causará problemas. Además de eso, si solo deshabilita eventos “touchmove” en ciertos elementos (por ejemplo, cuerpo si desea que la página no sea desplazable), tan pronto como esté habilitado en cualquier otro lugar, IOS causará una propagación imparable en Chrome cuando la URL la barra alterna

Si bien no puedo explicar este comportamiento, parece que la única forma de prevenir parece establecer la posición del cuerpo como fixed . El único problema es que perderá la posición del documento; esto es especialmente molesto en los modales, por ejemplo. Una forma de resolverlo sería usar estas funciones simples de VanillaJS:

 function disableDocumentScrolling() { if (document.documentElement.style.position != 'fixed') { // Get the top vertical offset. var topVerticalOffset = (typeof window.pageYOffset != 'undefined') ? window.pageYOffset : (document.documentElement.scrollTop ? document.documentElement.scrollTop : 0); // Set the document to fixed position (this is the only way around IOS' overscroll "feature"). document.documentElement.style.position = 'fixed'; // Set back the offset position by user negative margin on the fixed document. document.documentElement.style.marginTop = '-' + topVerticalOffset + 'px'; } } function enableDocumentScrolling() { if (document.documentElement.style.position == 'fixed') { // Remove the fixed position on the document. document.documentElement.style.position = null; // Calculate back the original position of the non-fixed document. var scrollPosition = -1 * parseFloat(document.documentElement.style.marginTop); // Remove fixed document negative margin. document.documentElement.style.marginTop = null; // Scroll to the original position of the non-fixed document. window.scrollTo(0, scrollPosition); } } 

Al utilizar esta solución, puede tener un documento fijo y cualquier otro elemento en su página puede desbordarse mediante el uso de CSS simple (por ejemplo, overflow: scroll; ). No hay necesidad de clases especiales ni nada más.

Aquí hay una solución compatible con zepto

  if (!$(e.target).hasClass('scrollable') && !$(e.target).closest('.scrollable').length > 0) { console.log('prevented scroll'); e.preventDefault(); window.scroll(0,0); return false; } 

este funciona para mí (javascript simple)

 var fixScroll = function (className, border) { // className = class of scrollElement(s), border: borderTop + borderBottom, due to offsetHeight var reg = new RegExp(className,"i"); var off = +border + 1; function _testClass(e) { var o = e.target; while (!reg.test(o.className)) if (!o || o==document) return false; else o = o.parentNode; return o;} document.ontouchmove = function(e) { var o = _testClass(e); if (o) { e.stopPropagation(); if (o.scrollTop == 0) { o.scrollTop += 1; e.preventDefault();}}} document.ontouchstart = function(e) { var o = _testClass(e); if (o && o.scrollHeight >= o.scrollTop + o.offsetHeight - off) o.scrollTop -= off;} } fixScroll("fixscroll",2); // assuming I have a 1px border in my DIV 

html:

 
content

Prueba esto Funcionará perfecto.

 $('body.overflow-hidden').delegate('#skrollr-body','touchmove',function(e){ e.preventDefault(); console.log('Stop skrollrbody'); }).delegate('.mfp-auto-cursor .mfp-content','touchmove',function(e){ e.stopPropagation(); console.log('Scroll scroll'); }); 

Tuve una suerte sorprendente con simple:

 body { height: 100vh; } 

Funciona de maravilla para deshabilitar el sobrecrecimiento de ventanas emergentes o menús y no obliga a las barras del navegador a aparecer como cuando se usa la posición: fija. PERO – debe guardar la posición de desplazamiento antes de configurar la altura fija y restaurarla cuando se oculta la ventana emergente; de ​​lo contrario, el navegador se desplazará a la parte superior.