Cómo crear un componente Historias

Descripción general básica sobre cómo crear una experiencia similar a las Historias de Instagram en la Web.

En esta publicación, quiero compartir ideas sobre cómo compilar un componente de Historias para la Web que sea responsivo, admita la navegación con el teclado y funcione en todos los navegadores.

Demostración

Si prefieres una demostración práctica para compilar este componente de Historias por tu cuenta, consulta el codelab del componente de Historias.

Si prefieres un video, aquí tienes una versión de este artículo en YouTube:

Descripción general

Dos ejemplos populares de la UX de Historias son las Historias de Snapchat y las Historias de Instagram (sin mencionar las flotas). En términos generales de UX, las Historias suelen ser un patrón centrado en los toques y exclusivo para dispositivos móviles para navegar por varias suscripciones. Por ejemplo, en Instagram, los usuarios abren la historia de un amigo y ven las fotos que contiene. Por lo general, lo hacen con muchos amigos a la vez. Si presiona el lado derecho del dispositivo, el usuario avanza a la siguiente historia de ese amigo. Si desliza el dedo hacia la derecha, el usuario avanza a otro amigo. Un componente de Story es bastante similar a un carrusel, pero permite navegar por un array multidimensional en lugar de un array unidimensional. Es como si hubiera un carrusel dentro de cada carrusel. 🤯

Es un array multidimensional visualizado con tarjetas. De izquierda a derecha, se muestra una pila de tarjetas con bordes morados, y, dentro de cada tarjeta, hay varias tarjetas con bordes cian. Lista dentro de una lista.
1er carrusel de amigos
2º carrusel "apilado" de historias
👍 Lista en una lista, también conocida como array multidimensional

Cómo elegir las herramientas adecuadas para el trabajo

En general, me resultó bastante sencillo compilar este componente gracias a algunas funciones críticas de la plataforma web. Veamos cuáles son.

Cuadrícula de CSS

Nuestro diseño no resultó ser una tarea difícil para CSS Grid, ya que está equipado con algunas formas poderosas de organizar el contenido.

Diseño de amigos

Nuestro wrapper de componente .stories principal es una vista de desplazamiento horizontal centrada en dispositivos móviles:

.stories {
  inline-size: 100vw;
  block-size: 100vh;

  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;

  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}

/* desktop constraint */
@media (hover: hover) and (min-width: 480px) {
  max-inline-size: 480px;
  max-block-size: 848px;
}
Usa el modo de dispositivo de las Herramientas para desarrolladores de Chrome para destacar las columnas creadas por la cuadrícula.

Desglosemos ese diseño grid:

  • Completamos explícitamente la ventana gráfica en dispositivos móviles con 100vh y 100vw, y restringimos el tamaño en computadoras de escritorio.
  • / separa nuestras plantillas de filas y columnas
  • auto-flow se traduce como grid-auto-flow: column
  • La plantilla de autoflujo es 100%, que, en este caso, es el ancho de la ventana de desplazamiento.

En un teléfono celular, piensa en esto como si el tamaño de la fila fuera la altura del viewport y cada columna fuera el ancho del viewport. Si continuamos con el ejemplo de las Historias de Snapchat y las Historias de Instagram, cada columna será la historia de un amigo. Queremos que las historias de amigos continúen fuera del viewport para que tengamos dónde desplazarnos. La cuadrícula creará tantas columnas como necesite para diseñar tu HTML para cada historia de amigos, lo que creará un contenedor de desplazamiento dinámico y responsivo para nosotros. La cuadrícula nos permitió centralizar todo el efecto.

Apilamiento

Para cada amigo, necesitamos sus historias en un estado listo para la paginación. Elegí una pila para prepararme para la animación y otros patrones divertidos. Cuando digo pila, me refiero a que la mires desde arriba, como un sándwich, no desde el costado.

Con la cuadrícula de CSS, podemos definir una cuadrícula de una sola celda (es decir, un cuadrado) en la que las filas y las columnas comparten un alias ([story]) y, luego, cada elemento secundario se asigna a ese espacio de una sola celda con alias:

.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
.story {
  grid-area: story;
  background-size: cover;
  
}

Esto permite que nuestro código HTML controle el orden de apilamiento y también mantiene todos los elementos en flujo. Observa que no tuvimos que hacer nada con el posicionamiento de absolute ni con z-index, y no tuvimos que corregir el cuadro con height: 100% ni width: 100%. La cuadrícula principal ya definió el tamaño de la ventana gráfica de la imagen de la historia, por lo que no fue necesario indicarle a ninguno de estos componentes de la historia que la completaran.

Puntos de ajuste de desplazamiento de CSS

La especificación de puntos de ajuste de desplazamiento de CSS facilita el bloqueo de elementos en el viewport durante el desplazamiento. Antes de que existieran estas propiedades de CSS, tenías que usar JavaScript, y era… complicado, por decirlo de alguna manera. Consulta Introducing CSS Scroll Snap Points de Sarah Drasner para obtener un excelente análisis sobre cómo usarlos.

Desplazamiento horizontal sin y con estilos scroll-snap-points. Sin ella, los usuarios pueden desplazarse libremente como de costumbre. Con él, el navegador se apoya suavemente en cada elemento.
elemento superior
.stories {
  display: grid;
  grid: 1fr / auto-flow 100%;
  gap: 1ch;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  overscroll-behavior: contain;
  touch-action: pan-x;
}
El elemento principal con sobredesplazamiento define el comportamiento de ajuste.
niño
.user {
  display: grid;
  grid: [story] 1fr / [story] 1fr;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}
Los niños y las niñas aceptan ser un objetivo de ajuste.

Elegí Scroll Snap Points por varios motivos:

  • Accesibilidad gratuita. La especificación de Scroll Snap Points indica que, de forma predeterminada, al presionar las teclas de flecha hacia la izquierda y flecha hacia la derecha, se debe avanzar por los puntos de ajuste.
  • Una especificación en crecimiento: La especificación de Scroll Snap Points recibe nuevas funciones y mejoras todo el tiempo, lo que significa que mi componente de Historias probablemente solo mejorará a partir de ahora.
  • Facilidad de implementación Los puntos de ajuste de desplazamiento están diseñados prácticamente para el caso de uso de paginación horizontal centrada en el tacto.
  • Inercia de estilo de plataforma libre. Cada plataforma se desplazará y se detendrá según su estilo, a diferencia de la inercia normalizada, que puede tener un estilo de desplazamiento y detención extraño.

Compatibilidad entre navegadores

Realizamos pruebas en Opera, Firefox, Safari y Chrome, además de Android y iOS. A continuación, se incluye un breve resumen de las funciones web en las que encontramos diferencias en las capacidades y la compatibilidad.

Sin embargo, algunos CSS no se aplicaron, por lo que actualmente algunas plataformas no tienen optimizaciones de UX. Me gustó no tener que administrar estas funciones y confío en que, con el tiempo, llegarán a otros navegadores y plataformas.

scroll-snap-stop

Los carruseles fueron uno de los principales casos de uso de UX que impulsaron la creación de la especificación de puntos de ajuste de desplazamiento de CSS. A diferencia de las Historias, un carrusel no siempre necesita detenerse en cada imagen después de que un usuario interactúa con él. Puede ser aceptable o incluso recomendable desplazarse rápidamente por el carrusel. Por otro lado, lo mejor es navegar por las historias de a una, y eso es exactamente lo que proporciona scroll-snap-stop.

.user {
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

En el momento de escribir esta entrada del blog, scroll-snap-stop solo se admite en navegadores basados en Chromium. Consulta Compatibilidad del navegador para obtener actualizaciones. Sin embargo, no es un bloqueo. Solo significa que, en los navegadores no compatibles, los usuarios pueden omitir a un amigo por accidente. Por lo tanto, los usuarios deberán tener más cuidado, o bien tendremos que escribir código JavaScript para asegurarnos de que un amigo omitido no se marque como visto.

Obtén más información en la especificación si te interesa.

overscroll-behavior

¿Alguna vez te desplazaste por una ventana modal y, de repente, comenzaste a desplazarte por el contenido que se encontraba detrás de ella? overscroll-behavior permite que el desarrollador atrape ese desplazamiento y nunca lo deje ir. Es ideal para todo tipo de ocasiones. El componente Mis historias lo usa para evitar que los gestos adicionales de deslizamiento y desplazamiento salgan del componente.

.stories {
  overflow-x: auto;
  overscroll-behavior: contain;
}

Safari y Opera fueron los 2 navegadores que no admitieron esta función, y eso está bien. Esos usuarios tendrán una experiencia de desplazamiento excesivo como a la que están acostumbrados y es posible que nunca noten esta mejora. Personalmente, soy un gran fan y me gusta incluirlo como parte de casi todas las funciones de desplazamiento excesivo que implemento. Es una adición inofensiva que solo puede mejorar la UX.

scrollIntoView({behavior: 'smooth'})

Cuando un usuario toca o hace clic y llega al final del conjunto de historias de un amigo, es hora de pasar al siguiente amigo en el conjunto de puntos de ajuste de desplazamiento. Con JavaScript, pudimos hacer referencia al siguiente amigo y solicitar que se desplazara para que se mostrara. La compatibilidad con los conceptos básicos de esto es excelente; todos los navegadores lo desplazaron a la vista. Sin embargo, no todos los navegadores lo hicieron 'smooth'. Esto solo significa que se desplazó hasta la vista en lugar de ajustarse.

element.scrollIntoView({
  behavior: 'smooth'
})

Safari era el único navegador que no admitía behavior: 'smooth' aquí. Consulta Compatibilidad del navegador para obtener actualizaciones.

Práctica

Ahora que sabes cómo lo hice, ¿cómo lo harías tú? Diversifiquemos nuestros enfoques y aprendamos todas las formas de crear en la Web. Crea un Glitch, envíame un tweet con tu versión y la agregaré a la sección Remixes de la comunidad que se encuentra más abajo.

Remixes de la comunidad