css - attribute - title html
Evita el desplazamiento del cuerpo pero permite el desplazamiento de superposición (17)
El comportamiento que desea evitar se llama encadenamiento de desplazamiento. Para desactivarlo, establezca
overscroll-behavior: contain;
en su superposición en CSS.
He estado buscando una solución de tipo "lightbox" que permita esto, pero aún no he encontrado una (por favor, sugiera si sabe de alguna).
El comportamiento que estoy tratando de recrear es como lo que verías en Pinterest al hacer clic en una imagen. La superposición es desplazable ( como en toda la superposición se mueve hacia arriba como una página en la parte superior de una página ) pero el cuerpo detrás de la superposición es fijo.
Intenté crear esto solo con CSS ( es decir, una superposición div
sobre toda la página y el cuerpo con overflow: hidden
), pero no impide que div
sea desplazable.
¿Cómo evitar que el cuerpo / página se desplace pero que se desplace dentro del contenedor de pantalla completa?
En mi caso, ninguna de estas soluciones funcionó en iPhone (iOS 11.0).
La única solución efectiva que funciona en todos mis dispositivos es esta: ios-10-safari-prevent-scrolling-behind-a-fixed-overlay-and-maintain-scroll-position
En términos generales, si desea que un padre (el cuerpo en este caso) evite que se desplace cuando un niño (la superposición en este caso) se desplaza, haga que el hijo sea un hermano del padre para evitar que el evento de desplazamiento aumente hasta el padre. En caso de que el padre sea el cuerpo, esto requiere un elemento de ajuste adicional:
<div id="content">
</div>
<div id="overlay">
</div>
Vea Desplácese a contenidos DIV particulares con la barra de desplazamiento principal del navegador para ver cómo funciona.
Encontré esta pregunta tratando de resolver el problema que tenía con mi página en Ipad y Iphone: body estaba desplazándose cuando estaba mostrando div divido como emergente con imagen.
Algunas respuestas son buenas, sin embargo, ninguna de ellas resolvió mi problema. Encontré la siguiente entrada de blog por Christoffer Pettersson. La solución presentada allí me ayudó a solucionar el problema que tenía con los dispositivos iOS y me ayudó a solucionar el problema de fondo de desplazamiento.
Seis cosas que aprendí sobre el desplazamiento de la banda elástica de iOS Safari
Como se sugirió, incluyo los puntos principales de la publicación del blog en caso de que el enlace quede desactualizado.
"Para deshabilitar que el usuario pueda desplazarse por la página de fondo mientras el" menú está abierto ", es posible controlar qué elementos deben permitirse desplazarse o no, aplicando algunos JavaScript y una clase CSS.
Sobre la base de esta respuesta de , puede controlar que los elementos con deshabilitar el desplazamiento no deben realizar su acción de desplazamiento predeterminada cuando se activa el evento de movimiento táctil.
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();
}
};
Y luego ponga la clase de desplazamiento deshabilitado en la página div:
<div class="page disable-scrolling">
La mayoría de las soluciones tienen el problema de que no conservan la posición de desplazamiento, así que eché un vistazo a cómo lo hace Facebook. Además de configurar el contenido subyacente en la position: fixed
, también establecieron la parte superior dinámicamente para retener la posición de desplazamiento:
scrollPosition = window.pageYOffset;
mainEl.style.top = -scrollPosition + ''px'';
Luego, cuando vuelva a quitar la superposición, deberá restablecer la posición de desplazamiento:
window.scrollTo(0, scrollPosition);
He creado un pequeño ejemplo para demostrar esta solución.
let overlayShown = false;
let scrollPosition = 0;
document.querySelector(''.toggle'').addEventListener(''click'', function() {
if (overlayShown) {
showOverlay();
} else {
removeOverlay();
}
overlayShown = !overlayShown;
});
function showOverlay() {
scrollPosition = window.pageYOffset;
const mainEl = document.querySelector(''.main-content'');
mainEl.style.top = -scrollPosition + ''px'';
document.body.classList.add(''show-overlay'');
}
function removeOverlay() {
document.body.classList.remove(''show-overlay'');
window.scrollTo(0, scrollPosition);
const mainEl = document.querySelector(''.main-content'');
mainEl.style.top = 0;
}
.main-content {
background-image: repeating-linear-gradient( lime, blue 103px);
width: 100%;
height: 200vh;
}
.show-overlay .main-content {
position: fixed;
left: 0;
right: 0;
overflow-y: scroll; /* render disabled scroll bar to keep the same width */
}
.overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
overflow: auto;
}
.show-overlay .overlay {
display: block;
}
.overlay-content {
margin: 50px;
background-image: repeating-linear-gradient( grey, grey 20px, black 20px, black 40px);
height: 120vh;
}
.toggle {
position: fixed;
top: 5px;
left: 15px;
padding: 10px;
background: red;
}
<main class="main-content"></main>
<div class="overlay">
<div class="overlay-content"></div>
</div>
<button class="toggle">Overlay</button>
La respuesta elegida es correcta, pero tiene algunas limitaciones:
- Los "lanzamientos" súper duros con el dedo aún se desplazarán
<body>
en el fondo - Al abrir el teclado virtual al presionar una
<input>
en el modal, todos los desplazamientos futuros se dirigirán a<body>
No tengo una solución para el primer problema, pero quería arrojar algo de luz sobre el segundo. Confusamente, Bootstrap solía tener el problema del teclado documentado, pero afirmaron que estaba arreglado, citando http://output.jsbin.com/cacido/quiet como un ejemplo de la solución.
De hecho, ese ejemplo funciona bien en iOS con mis pruebas. Sin embargo, actualizarlo al último Bootstrap (v4) lo rompe.
En un intento por descubrir cuál era la diferencia entre ellos, reduje un caso de prueba para que ya no dependiera de Bootstrap, http://codepen.io/WestonThayer/pen/bgZxBG .
Los factores decisivos son extraños. Evitar el problema del teclado parece requerir que background-color
no se establezca en la raíz <div>
contiene el modal y el contenido del modal debe estar anidado en otro <div>
, que puede tener background-color
conjunto de background-color
.
Para probarlo, descomente la línea de abajo en el ejemplo de Codepen:
.modal {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 2;
display: none;
overflow: hidden;
-webkit-overflow-scrolling: touch;
/* UNCOMMENT TO BREAK */
/* background-color: white; */
}
Me gustaría agregar a las respuestas anteriores porque traté de hacer eso, y se rompió algo de diseño tan pronto como cambié el cuerpo a la posición: fijo. Para evitar eso, también tuve que ajustar la altura del cuerpo al 100%:
function onMouseOverOverlay(over){
document.getElementsByTagName("body")[0].style.overflowY = (over?"hidden":"scroll");
document.getElementsByTagName("html")[0].style.position = (over?"fixed":"static");
document.getElementsByTagName("html")[0].style.height = (over?"100%":"auto");
}
No utilice overflow: hidden;
en el body
Se desplaza automáticamente todo a la parte superior. No hay necesidad de JavaScript tampoco. Hacer uso de overflow: auto;
. Esta solución funciona incluso con Safari móvil:
Estructura HTML
<div class="overlay">
<div class="overlay-content"></div>
</div>
<div class="background-content">
lengthy content here
</div>
Estilo
.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;
}
Vea la demostración here y el código fuente here .
Actualizar:
Para las personas que desean la barra espaciadora del teclado, la página arriba / abajo para trabajar: debe concentrarse en la superposición, por ejemplo, hacer clic en ella o manualmente, concentrarse en ella antes de que esta parte del div
responda al teclado. Lo mismo ocurre cuando la superposición está "apagada", ya que simplemente la mueve hacia un lado. De lo contrario, para el navegador, estos son solo dos div
normales y no sabría por qué debería enfocarse en ninguno de ellos.
Para dispositivos táctiles, intente agregar un div transparente de 1px de ancho y 101vh
de altura mínima en la envoltura de la superposición. Luego agregue -webkit-overflow-scrolling:touch; overflow-y: auto;
-webkit-overflow-scrolling:touch; overflow-y: auto;
a la envoltura. Esto engaña al safari móvil para que piense que la superposición es desplazable, interceptando así el evento táctil del cuerpo.
Aquí hay una página de muestra. Abierto en safari móvil: http://www.originalfunction.com/overlay.html
https://gist.github.com/YarGnawh/90e0647f21b5fa78d2f678909673507f
Si desea evitar el desplazamiento excesivo en ios, puede agregar una posición fija a su clase .noscroll
body.noscroll{
position:fixed;
overflow:hidden;
}
Si la intención es deshabilitar en dispositivos móviles / táctiles, la forma más directa de hacerlo es mediante touch-action: none;
.
Ejemplo:
const app = document.getElementById(''app'');
const overlay = document.getElementById(''overlay'');
let body = '''';
for (let index = 0; index < 500; index++) {
body += index + ''<br />'';
}
app.innerHTML = body;
app.scrollTop = 200;
overlay.innerHTML = body;
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
#app {
background: #f00;
position: absolute;
height: 100%;
width: 100%;
overflow-y: scroll;
line-height: 20px;
}
#overlay {
background: rgba(0,0,0,.5);
position: fixed;
top: 0;
left: 0;
right: 0;
height: 100%;
padding: 0 0 0 100px;
overflow: scroll;
}
<div id=''app''></div>
<div id=''overlay''></div>
(El ejemplo no funciona en el contexto de Desbordamiento de pila. Deberá volver a crearlo en una página independiente).
Si desea deshabilitar el desplazamiento del contenedor #app
, simplemente agregue touch-action: none;
.
Usa el siguiente HTML:
<body>
<div class="page">Page content here</div>
<div class="overlay"></div>
</body>
Luego JavaScript para interceptar y detener el desplazamiento:
$(".page").on("touchmove", function(event) {
event.preventDefault()
});
Luego, para que las cosas vuelvan a la normalidad:
$(".page").off("touchmove");
Utilice el siguiente código para desactivar y activar la barra de desplazamiento.
Scroll = (
function(){
var x,y;
function hndlr(){
window.scrollTo(x,y);
//return;
}
return {
disable : function(x1,y1){
x = x1;
y = y1;
if(window.addEventListener){
window.addEventListener("scroll",hndlr);
}
else{
window.attachEvent("onscroll", hndlr);
}
},
enable: function(){
if(window.removeEventListener){
window.removeEventListener("scroll",hndlr);
}
else{
window.detachEvent("onscroll", hndlr);
}
}
}
})();
//for disabled scroll bar.
Scroll.disable(0,document.body.scrollTop);
//for enabled scroll bar.
Scroll.enable();
Vale la pena señalar que a veces agregar "desbordamiento: oculto" a la etiqueta del cuerpo no hace el trabajo. En esos casos, también deberá agregar la propiedad a la etiqueta html.
html, body {
overflow: hidden;
}
prueba esto
var mywindow = $(''body''), navbarCollap = $(''.navbar-collapse'');
navbarCollap.on(''show.bs.collapse'', function(x) {
mywindow.css({visibility: ''hidden''});
$(''body'').attr("scroll","no").attr("style", "overflow: hidden");
});
navbarCollap.on(''hide.bs.collapse'', function(x) {
mywindow.css({visibility: ''visible''});
$(''body'').attr("scroll","yes").attr("style", "");
});
overscroll-behavior
propiedad css de overscroll-behavior
permite anular el comportamiento de desplazamiento de desbordamiento predeterminado del navegador al llegar a la parte superior / inferior del contenido.
Solo agrega los siguientes estilos a la superposición:
.overlay {
overscroll-behavior: contain;
...
}
Actualmente funciona en Chrome, Firefox e IE ( caniuse )
Para más detalles revisa el artículo de los desarrolladores de google .
Teoría
Al observar la implementación actual del sitio pinterest (podría cambiar en el futuro), cuando se abre la superposición, se aplica una clase noscroll
al elemento del body
y se overflow: hidden
se establece, por lo tanto, el body
ya no es desplazable.
La superposición (creada sobre la marcha o ya dentro de la página y visible a través de la display: block
, no hace ninguna diferencia) tiene la position : fixed
y overflow-y: scroll
, con las propiedades top
, left
, right
e bottom
establecidas en 0
: este estilo hace que la superposición llene toda la ventana gráfica.
El div
dentro de la superposición está en su lugar solo en position: static
entonces la barra de desplazamiento vertical que se ve está relacionada con ese elemento. Como resultado, el contenido es desplazable pero la superposición permanece fija.
Cuando cierras el zoom, ocultas la superposición (a través de la display: none
) y luego también puedes eliminarlo por completo a través de javascript (o solo el contenido que está dentro, tú decides cómo inyectarlo).
Como paso final, también debe eliminar la clase noscroll
del body
(para que la propiedad de desbordamiento vuelva a su valor inicial)
Código
(Funciona cambiando el atributo aria-hidden
de la superposición para mostrarlo, ocultarlo y aumentar su accesibilidad).
Margen
(botón de abrir)
<button type="button" class="open-overlay">OPEN LAYER</button>
(botón de superposición y cierre)
<section class="overlay" aria-hidden="true">
<div>
<h2>Hello, I''m the overlayer</h2>
...
<button type="button" class="close-overlay">CLOSE LAYER</button>
</div>
</section>
CSS
.noscroll {
overflow: hidden;
}
.overlay {
position: fixed;
overflow-y: scroll;
top: 0; right: 0; bottom: 0; left: 0; }
[aria-hidden="true"] { display: none; }
[aria-hidden="false"] { display: block; }
Javascript (vainilla-JS)
var body = document.body,
overlay = document.querySelector(''.overlay''),
overlayBtts = document.querySelectorAll(''button[class$="overlay"]'');
[].forEach.call(overlayBtts, function(btt) {
btt.addEventListener(''click'', function() {
/* Detect the button class name */
var overlayOpen = this.className === ''open-overlay'';
/* Toggle the aria-hidden state on the overlay and the
no-scroll class on the body */
overlay.setAttribute(''aria-hidden'', !overlayOpen);
body.classList.toggle(''noscroll'', overlayOpen);
/* On some mobile browser when the overlay was previously
opened and scrolled, if you open it again it doesn''t
reset its scrollTop property */
overlay.scrollTop = 0;
}, false);
});
Finalmente, aquí hay otro ejemplo en el que la superposición se abre con un efecto de fundido de entrada mediante una transition
CSS aplicada a la propiedad de opacity
. También se aplica un padding-right
para evitar un reflujo en el texto subyacente cuando desaparece la barra de desplazamiento.
CSS
.noscroll { overflow: hidden; }
@media (min-device-width: 1025px) {
/* not strictly necessary, just an experiment for
this specific example and couldn''t be necessary
at all on some browser */
.noscroll {
padding-right: 15px;
}
}
.overlay {
position: fixed;
overflow-y: scroll;
top: 0; left: 0; right: 0; bottom: 0;
}
[aria-hidden="true"] {
transition: opacity 1s, z-index 0s 1s;
width: 100vw;
z-index: -1;
opacity: 0;
}
[aria-hidden="false"] {
transition: opacity 1s;
width: 100%;
z-index: 1;
opacity: 1;
}