javascript - debugger - iOS 10 Safari: evita el desplazamiento detrás de una superposición fija y mantiene la posición de desplazamiento
safari developer (7)
No puedo evitar que el contenido del cuerpo principal se desplace mientras se muestra una superposición de posición fija. Muchas veces se hicieron preguntas similares, pero todas las técnicas que funcionaron anteriormente no parecen funcionar en Safari en iOS 10. Esto parece ser un problema reciente.
Algunas notas:
- Puedo deshabilitar el desplazamiento si configuro tanto el
html
como elbody
para que seoverflow: hidden
, sin embargo, eso hace que el contenido del cuerpo se desplace hacia la parte superior. - Si el contenido de la superposición es lo suficientemente largo como para que pueda desplazarse, el desplazamiento se desactiva correctamente para el contenido de la página principal. Si el contenido de la superposición no es lo suficientemente largo como para provocar el desplazamiento, puede desplazarse por el contenido de la página principal.
-
touchmove
una función javascript de http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/ que desactiva eltouchmove
mientras se muestra la superposición. Esto funcionó anteriormente, pero ya no funciona.
Aquí está la fuente HTML completa:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<style type="text/css">
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
font-family: arial;
}
#overlay {
display: none;
position: fixed;
z-index: 9999;
left: 0;
right: 0;
top: 0;
bottom: 0;
overflow: scroll;
color: #fff;
background: rgba(0, 0, 0, 0.5);
}
#overlay span {
position: absolute;
display: block;
right: 10px;
top: 10px;
font-weight: bold;
font-size: 44px;
cursor: pointer;
}
#overlay p {
display: block;
padding: 100px;
font-size: 36px;
}
#page {
width: 100%;
height: 100%;
}
a {
font-weight: bold;
color: blue;
}
</style>
<script>
$(function() {
$(''a'').click(function(e) {
e.preventDefault();
$(''body'').css(''overflow'', ''hidden'');
$(''#page'').addClass(''disable-scrolling''); // for touchmove technique below
$(''#overlay'').fadeIn();
});
$(''#overlay span'').click(function() {
$(''body'').css(''overflow'', ''auto'');
$(''#page'').removeClass(''disable-scrolling''); // for touchmove technique below
$(''#overlay'').fadeOut();
});
});
/* Technique from http://blog.christoffer.me/six-things-i-learnt-about-ios-safaris-rubber-band-scrolling/ */
document.ontouchmove = function ( event ) {
var isTouchMoveAllowed = true, target = event.target;
while ( target !== null ) {
if ( target.classList && target.classList.contains( ''disable-scrolling'' ) ) {
isTouchMoveAllowed = false;
break;
}
target = target.parentNode;
}
if ( !isTouchMoveAllowed ) {
event.preventDefault();
}
};
</script>
</head>
<body>
<div id="overlay">
<span>×</span>
<p>fixed popover</p>
</div>
<div id="page">
<strong>this is the top</strong><br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
lots of scrollable content<br>
asdfasdf<br>
<br>
<div><a href="#">Show Popover</a></div>
<br>
<br>
</div>
</body>
</html>
Combiné el enfoque de Bohdan Didukh con mi enfoque anterior para crear un paquete npm fácil de usar para deshabilitar / habilitar el desplazamiento del cuerpo.
https://github.com/willmcpo/body-scroll-lock
Para obtener más detalles sobre cómo funciona la solución, lea https://medium.com/jsdownunder/locking-body-scroll-for-all-devices-22def9615177
Cuando se abre la superposición, puede agregar una clase como prevent-scroll
al body
para evitar el desplazamiento de los elementos detrás de la superposición:
body.prevent-scroll {
position: fixed;
overflow: hidden;
width: 100%;
height: 100%;
}
Encontré el código en github . Funciona en Safari en iOS 10,11,12.
/* ScrollClass */
class ScrollClass {
constructor () {
this.$body = $(''body'');
this.styles = {
disabled: {
''height'': ''100%'',
''overflow'': ''hidden'',
},
enabled: {
''height'': '''',
''overflow'': '''',
}
};
}
disable ($element = $(window)) {
let disabled = false;
let scrollTop = window.pageYOffset;
$element
.on(''scroll.disablescroll'', (event) => {
event.preventDefault();
this.$body.css(this.styles.disabled);
window.scrollTo(0, scrollTop);
return false;
})
.on(''touchstart.disablescroll'', () => {
disabled = true;
})
.on(''touchmove.disablescroll'', (event) => {
if (disabled) {
event.preventDefault();
}
})
.on(''touchend.disablescroll'', () => {
disabled = false;
});
}
enable ($element = $(window)) {
$element.off(''.disablescroll'');
this.$body.css(this.styles.enabled);
}
}
utilizar:
Scroll = new ScrollClass();
Scroll.disable();// disable scroll for $(window)
Scroll.disable($(''element''));// disable scroll for $(''element'')
Scroll.enable();// enable scroll for $(window)
Scroll.enable($(''element''));// enable scroll for $(''element'')
Espero que te ayude.
Intenté encontrar una solución limpia a esto durante mucho tiempo, y lo que parece que me ha funcionado mejor es establecer pointer-events: none;
en el cuerpo, y luego pointer-events: auto;
explícitamente en el elemento que quiero permitir el desplazamiento en.
Para aquellos que usan React, he tenido éxito al poner la solución de @ bohdan-didukh en el método componentDidMount en un componente. Algo como esto (enlace visible a través de navegadores móviles):
class Hello extends React.Component {
componentDidMount = () => {
var _overlay = document.getElementById(''overlay'');
var _clientY = null; // remember Y position on touch start
function isOverlayTotallyScrolled() {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
return _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight;
}
function disableRubberBand(event) {
var clientY = event.targetTouches[0].clientY - _clientY;
if (_overlay.scrollTop === 0 && clientY > 0) {
// element is at the top of its scroll
event.preventDefault();
}
if (isOverlayTotallyScrolled() && clientY < 0) {
//element is at the top of its scroll
event.preventDefault();
}
}
_overlay.addEventListener(''touchstart'', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
_clientY = event.targetTouches[0].clientY;
}
}, false);
_overlay.addEventListener(''touchmove'', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
disableRubberBand(event);
}
}, false);
}
render() {
// border and padding just to illustrate outer scrolling disabled
// when scrolling in overlay, and enabled when scrolling in outer
// area
return <div style={{ border: "1px solid red", padding: "48px" }}>
<div id=''overlay'' style={{ border: "1px solid black", overflowScrolling: ''touch'', WebkitOverflowScrolling: ''touch'' }}>
{[...Array(10).keys()].map(x => <p>Text</p>)}
</div>
</div>;
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById(''container'')
);
Visible a través del móvil: https://jsbin.com/wiholabuka
Enlace editable: https://jsbin.com/wiholabuka/edit?html,js,output
Trate de agregar a la altura máxima del cuerpo: 100vh;
por favor, agregue -webkit-overflow-scrolling: touch;
al elemento #overlay
.
Y agregue por favor este código javascript al final de la etiqueta del cuerpo:
(function () {
var _overlay = document.getElementById(''overlay'');
var _clientY = null; // remember Y position on touch start
_overlay.addEventListener(''touchstart'', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
_clientY = event.targetTouches[0].clientY;
}
}, false);
_overlay.addEventListener(''touchmove'', function (event) {
if (event.targetTouches.length === 1) {
// detect single touch
disableRubberBand(event);
}
}, false);
function disableRubberBand(event) {
var clientY = event.targetTouches[0].clientY - _clientY;
if (_overlay.scrollTop === 0 && clientY > 0) {
// element is at the top of its scroll
event.preventDefault();
}
if (isOverlayTotallyScrolled() && clientY < 0) {
//element is at the top of its scroll
event.preventDefault();
}
}
function isOverlayTotallyScrolled() {
// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#Problems_and_solutions
return _overlay.scrollHeight - _overlay.scrollTop <= _overlay.clientHeight;
}
}())
Espero que te ayude.