A modo de resumen
La propiedad overscroll-behavior
de CSS permite a los desarrolladores anular el comportamiento de desplazamiento de desbordamiento predeterminado del navegador cuando se llega a la parte superior o inferior del contenido. Los casos de uso incluyen inhabilitar la función de deslizar para actualizar en dispositivos móviles, quitar el brillo de desplazamiento excesivo y los efectos de goma elástica, y evitar que el contenido de la página se desplace cuando está debajo de un elemento modal o superpuesto.
Segundo plano
Límites de desplazamiento y encadenamiento de desplazamiento
El desplazamiento es una de las formas más fundamentales de interactuar con una página, pero ciertos patrones de UX pueden ser difíciles de manejar debido a los comportamientos predeterminados poco convencionales del navegador. Como ejemplo, toma un panel lateral de apps con una gran cantidad de elementos que el usuario podría tener que desplazarse. Cuando llega al final, el contenedor de desbordamiento deja de desplazarse porque no hay más contenido para consumir. En otras palabras, el usuario alcanza un "límite de desplazamiento". Pero observa lo que sucede si el usuario continúa desplazándose. El contenido detrás del panel lateral comienza a desplazarse. El desplazamiento lo ocupa el contenedor superior; en el ejemplo, la página principal en sí.
Resulta que este comportamiento se denomina encadenamiento de desplazamiento, el comportamiento predeterminado del navegador cuando se desplaza el contenido. A menudo, la configuración predeterminada es bastante agradable, pero a veces no es deseable ni inesperado. Es posible que algunas apps quieran proporcionar una experiencia del usuario diferente cuando alcance un límite de desplazamiento.
El efecto de deslizar para actualizar
Tirar para actualizar es un gesto intuitivo popular por las apps para dispositivos móviles como Facebook y Twitter. Si deslizas hacia abajo un feed de redes sociales y lo sueltas, se crea un espacio nuevo para que se carguen publicaciones más recientes. De hecho, esta UX en particular se volvió tan popular que los navegadores para dispositivos móviles, como Chrome en Android, adoptaron el mismo efecto. Si deslizas el dedo hacia abajo en la parte superior de la página, se actualiza toda la página:
En situaciones como la AWP de Twitter, podría tener sentido inhabilitar la acción nativa de deslizar para actualizar. ¿Por qué? En esta
app, es probable que no quieras que el usuario actualice la página por accidente. También es posible ver una animación de actualización doble. Como alternativa, podría ser mejor personalizar la acción del navegador y alinearla más con el desarrollo de la marca del sitio. Lo lamentable es que este tipo de personalización es difícil de realizar. Los desarrolladores terminan escribiendo JavaScript innecesario, agregan objetos de escucha de toque no pasivos (que bloquean el desplazamiento) o colocan toda la página en un <div>
de 100 vw/vh (para evitar que la página se desborde). Estas soluciones alternativas tienen efectos negativos bien documentados en el rendimiento del desplazamiento.
¡Podemos hacerlo mejor!
Presentamos overscroll-behavior
La propiedad overscroll-behavior
es una nueva función de CSS que controla el comportamiento de lo que sucede cuando te desplazas por un contenedor (incluida la página en sí). Puedes usarlo para cancelar la encadenación de desplazamiento, inhabilitar o personalizar la acción de deslizar para actualizar, inhabilitar los efectos de goma elástica en iOS (cuando Safari implementa overscroll-behavior
) y mucho más.
Lo mejor es que usar overscroll-behavior
no afecta negativamente el rendimiento de la página, como los hacks mencionados en la introducción.
La propiedad toma tres valores posibles:
- auto: Es el valor predeterminado. Los desplazamientos que se originan en el elemento pueden propagarse a los elementos superiores.
- contain: Evita el encadenamiento de desplazamiento. Los desplazamientos no se propagan a los principales, pero se muestran los efectos locales dentro del nodo. Por ejemplo, el efecto de brillo de desplazamiento excesivo en Android o el efecto de goma elástica en iOS, que notifica al usuario cuando alcanza un límite de desplazamiento. Nota: El uso de
overscroll-behavior: contain
en el elementohtml
evita las acciones de navegación de desplazamiento excesivo. - none: Es igual que
contain
, pero también evita los efectos de desplazamiento excesivo dentro del nodo (p.ej., el brillo de desplazamiento excesivo de Android o el efecto de goma elástica de iOS).
Analicemos algunos ejemplos para ver cómo usar overscroll-behavior
.
Evita que los desplazamientos escapen de un elemento de posición fija
Situación del cuadro de chat
Considera un cuadro de chat con posición fija que se ubique en la parte inferior de la página. La intención es que el cuadro de chat sea un componente independiente y que se desplace por separado del contenido que se encuentra detrás de él. Sin embargo, debido al encadenamiento de desplazamiento, el documento comienza a desplazarse en cuanto el usuario llega al último mensaje del historial de chat.
Para esta app, es más apropiado que los desplazamientos que se originan dentro del cuadro de chat permanezcan dentro del chat. Para hacerlo, podemos agregar overscroll-behavior: contain
al elemento que contiene los mensajes de chat:
#chat .msgs {
overflow: auto;
overscroll-behavior: contain;
height: 300px;
}
En esencia, estamos creando una separación lógica entre el contexto de desplazamiento del cuadro de chat y la página principal. El resultado final es que la página principal permanece fija cuando el usuario llega a la parte superior o inferior del historial de chat. Los desplazamientos que comienzan en el cuadro de chat no se propagan.
Situación de superposición de la página
Otra variación de la situación de "desplazamiento inferior" es cuando ves contenido que se desplaza detrás de una superposición de posición fija. Te damos una overscroll-behavior
de regalo. El navegador intenta ser útil, pero termina haciendo que el sitio parezca tener errores.
Ejemplo: Ventana modal con y sin overscroll-behavior: contain
:
Cómo inhabilitar el gesto de deslizar para actualizar
Desactivar la acción de deslizar para actualizar es una sola línea de CSS. Solo evita el encadenamiento de desplazamiento en todo el elemento que define el viewport. En la mayoría de los casos, es <html>
o <body>
:
body {
/* Disables pull-to-refresh but allows overscroll glow effects. */
overscroll-behavior-y: contain;
}
Con esta simple adición, corregimos las animaciones de doble deslizamiento para actualizar en la demo de cuadro de chat y, en su lugar, podemos implementar un efecto personalizado que usa una animación de carga más ordenada. Además, toda la bandeja de entrada se desenfoca a medida que esta se actualiza:
Este es un fragmento del código completo:
<style>
body.refreshing #inbox {
filter: blur(1px);
touch-action: none; /* prevent scrolling */
}
body.refreshing .refresher {
transform: translate3d(0,150%,0) scale(1);
z-index: 1;
}
.refresher {
--refresh-width: 55px;
pointer-events: none;
width: var(--refresh-width);
height: var(--refresh-width);
border-radius: 50%;
position: absolute;
transition: all 300ms cubic-bezier(0,0,0.2,1);
will-change: transform, opacity;
...
}
</style>
<div class="refresher">
<div class="loading-bar"></div>
<div class="loading-bar"></div>
<div class="loading-bar"></div>
<div class="loading-bar"></div>
</div>
<section id="inbox"><!-- msgs --></section>
<script>
let _startY;
const inbox = document.querySelector('#inbox');
inbox.addEventListener('touchstart', e => {
_startY = e.touches[0].pageY;
}, {passive: true});
inbox.addEventListener('touchmove', e => {
const y = e.touches[0].pageY;
// Activate custom pull-to-refresh effects when at the top of the container
// and user is scrolling up.
if (document.scrollingElement.scrollTop === 0 && y > _startY &&
!document.body.classList.contains('refreshing')) {
// refresh inbox.
}
}, {passive: true});
</script>
Inhabilita el brillo de sobredesplazamiento y los efectos de efecto de goma
Para inhabilitar el efecto de rebote cuando alcanzas un límite de desplazamiento, usa overscroll-behavior-y: none
:
body {
/* Disables pull-to-refresh and overscroll glow effect.
Still keeps swipe navigations. */
overscroll-behavior-y: none;
}
Demostración completa
En conjunto, la demostración completa del cuadro de chat usa overscroll-behavior
para crear una animación personalizada de deslizamiento para actualizar y para inhabilitar los desplazamientos que salen del widget del cuadro de chat. Esto proporciona una experiencia del usuario óptima que habría sido difícil lograr sin CSS overscroll-behavior
.