Tema representativo de entrevista

Entrevista frontend: ¿Cómo diseñarías animaciones degradables controladas por scroll con CSS?

FrontendIntermedio
Equipo editorial de Offer.ccPublicado Actualizado

Pregunta

Diseña una barra de progreso de lectura y un efecto de entrada para tarjetas con líneas de tiempo de CSS controladas por scroll, y explica los contenedores de scroll, las líneas de tiempo de visualización (view timelines), la degradación elegante (fallback) y la accesibilidad.

1. Pregunta y contexto

Una página de contenido necesita una barra de progreso de lectura en la parte superior, y las tarjetas deben aparecer gradualmente (fade in) a medida que ingresan a un contenedor con scroll. El equipo utilizó inicialmente un event listener de scroll y requestAnimationFrame, pero los dispositivos de gama baja muestran tirones (jank) en el hilo principal. Rediséñalo utilizando animaciones de CSS controladas por scroll (Scroll-driven Animations), explica el progreso de scroll frente al progreso de visualización (view progress), y cubre navegadores no compatibles, reducción de movimiento y verificación.

2. Qué evalúa el entrevistador

  • Si comprendes que las animaciones de CSS pueden seguir una línea de tiempo de scroll o una línea de tiempo de visualización en lugar de la línea de tiempo predeterminada basada en el tiempo.
  • Si distingues entre scroll(), que rastrea la posición de un contenedor de scroll, y view(), que rastrea el rango de visibilidad de un elemento dentro de su contenedor de scroll más cercano.
  • Si manejas líneas de tiempo con nombre, rangos de animación, prerrequisitos de overflow y el orden de reinicio de las propiedades abreviadas (shorthand).
  • Si la compatibilidad, el rendimiento, la lectura mediante teclado, la reducción de movimiento y una alternativa sin JavaScript forman parte del diseño.

3. Aclaraciones a solicitar antes de responder

  1. ¿La barra de progreso debe seguir al documento o al contenedor de scroll de un artículo interno?
  2. ¿Una tarjeta debe animarse solo una vez al entrar, o debe avanzar y retroceder con su fracción visible?
  3. ¿Qué navegadores se requieren y qué degradación visual y funcional es aceptable?
  4. ¿Los usuarios que prefieren movimiento reducido aún deben ver los cambios de progreso? ¿Podría el movimiento afectar el orden de lectura o el foco?

4. Estructura de respuesta en 30 segundos

Vincularía la barra de lectura a la línea de tiempo de progreso de scroll del contenedor y vincularía las tarjetas a líneas de tiempo de progreso de visualización. scroll() representa el progreso desde el inicio hasta el final del contenedor de scroll; view() representa la entrada y salida de un elemento del rango visible de su contenedor más cercano. Los keyframes siguen definiendo el cambio visual, mientras que animation-timeline suministra el progreso. El contenedor debe tener una distancia desplazable real y el rango de animación debe ser explícito. Los navegadores no compatibles mantienen un indicador de progreso estático o usan una alternativa ligera y limitada mediante JavaScript (throttled); el contenido principal nunca depende del movimiento. Agregaría comprobaciones de supports, comportamiento para reduced-motion, pruebas de teclado y mediciones en dispositivos de gama baja.

5. Respuesta detallada paso a paso

Paso 1: Establecer la semántica de la línea de tiempo

Una línea de tiempo de progreso de scroll es impulsada por la posición de un contenedor de scroll, avanzando normalmente del 0% al inicio al 100% al final. Una línea de tiempo de progreso de visualización es impulsada por el rango visible del elemento objetivo en relación con su contenedor de scroll más cercano, lo cual se adapta a tarjetas que entran y salen del viewport. Ambas se basan en el modelo de líneas de tiempo de CSS Animations y Web Animations API.

Paso 2: Implementar la barra de progreso de lectura

Haz que el contenedor del artículo tenga un overflow real, asigna un nombre a su línea de tiempo de scroll y apunta la propiedad animation-timeline del elemento de progreso a ese nombre. No definas animation-timeline sin keyframes, y no trates un contenedor sin rango de scroll como una línea de tiempo utilizable.

css
.article-scroller {
  overflow-y: auto;
  scroll-timeline-name: --article-scroll;
  scroll-timeline-axis: block;
}

.reading-progress {
  transform-origin: left center;
  animation: grow-progress linear;
  animation-timeline: --article-scroll;
}

@keyframes grow-progress {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

Paso 3: Implementar una línea de tiempo de visualización para tarjetas

Una tarjeta puede usar una línea de tiempo view() anónima que rastree la visibilidad en el contenedor de scroll ancestro más cercano. Para un control más preciso, asígnale un nombre con view-timeline-name y ajusta los límites de inicio y fin con view-timeline-inset. El rango debe coincidir con la zona visible prevista para que una tarjeta no complete toda su animación en cuanto toque un borde.

css
.card {
  animation: reveal-card linear both;
  animation-timeline: view(block 15% 15%);
}

@keyframes reveal-card {
  entry 0% { opacity: 0; transform: translateY(1rem); }
  cover 45% { opacity: 1; transform: translateY(0); }
  exit 100% { opacity: 0.6; }
}

Paso 4: Manejar rangos y trampas de las propiedades abreviadas

Las líneas de tiempo con nombre y anónimas requieren la relación de contenedor de scroll correcta; una discrepancia en overflow, eje o jerarquía de elementos puede dejar la línea de tiempo sin progreso. Declara animation-timeline después de la propiedad abreviada animation porque esta restablece los componentes de línea de tiempo omitidos a sus valores predeterminados. Utiliza animation-range o keyframes de rango para fases explícitas de entry, cover y exit, y luego realiza pruebas en los navegadores objetivo.

Paso 5: Diseñar la degradación elegante y la verificación de accesibilidad

Utiliza @supports para detectar animation-timeline. Cuando la mejora progresiva no esté disponible, mantén un indicador de progreso estático, un orden de lectura normal y un contraste legible. Si una alternativa dinámica es necesaria, aplica throttle al trabajo de scroll y evita recalcular el diseño (layout) repetidamente. Bajo prefers-reduced-motion: reduce, elimina la traslación y el movimiento continuo mientras conservas la información de progreso y el orden de foco. Prueba el desplazamiento por teclado, lectores de pantalla, desplazamiento inverso rápido, contenedores de scroll anidados y el tiempo de renderizado de cuadros en dispositivos de gama baja.

6. Respuesta de muestra de alta calidad

Vincularía la barra de lectura a la línea de tiempo de progreso de scroll del contenedor del artículo y las tarjetas a líneas de tiempo de progreso de visualización en su contenedor más cercano. La primera representa la posición de scroll del 0% al 100%; la segunda representa el elemento entrando, cubriendo y saliendo del rango visible. Verificaría el overflow real y luego definiría keyframes y animation-timeline en un orden que evite que la propiedad abreviada restablezca la línea de tiempo. @supports proporcionaría una alternativa estática, utilizando JavaScript con throttle solo cuando sea necesario. Reduced-motion eliminaría la traslación y los efectos continuos preservando el contenido, el progreso y el foco. Verificaría el uso de teclado, lectores de pantalla, scroll anidado y el frame time en dispositivos de gama baja.

7. Errores comunes

  • Tratar scroll() y view() como el mismo progreso → las tarjetas no siguen la visibilidad → explica primero la posición del contenedor frente a la visibilidad del elemento.
  • Declarar una línea de tiempo de scroll en un contenedor que no tiene overflow → no hay progreso en la animación → verifica el tamaño del contenido, el overflow y el eje.
  • Dejar que la propiedad abreviada animation sobreescriba animation-timeline → se restaura la línea de tiempo predeterminada → declara animation-timeline nuevamente después de la abreviatura.
  • Mostrar contenido únicamente en navegadores modernos → los navegadores antiguos pierden el comportamiento principal → mantén un indicador estático y un orden de lectura normal.
  • Establecer solo la opacidad en cero para movimiento reducido → la retroalimentación visual desaparece → elimina la traslación y el movimiento continuo mientras mantienes el estado semántico y visible.

8. Preguntas de seguimiento y respuestas

Pregunta de seguimiento 1: ¿Cuándo se utiliza una línea de tiempo de scroll frente a una línea de tiempo de visualización?

Utiliza una línea de tiempo de scroll para el progreso a lo largo de toda una región con desplazamiento. Utiliza una línea de tiempo de visualización para un elemento que entra, cubre y sale de un contenedor de scroll. El factor decisivo es el origen del progreso, no si JavaScript está presente.

Pregunta de seguimiento 2: ¿Por qué podría estar declarada animation-timeline pero no producir ninguna animación?

Las causas comunes son la falta de un rango de scroll real, una discrepancia de ejes, un nombre de línea de tiempo fuera de la relación de ancestros o una propiedad abreviada de animación posterior que restablece la línea de tiempo. Verifica el overflow, las relaciones de la línea de tiempo y el orden de declaración en esa secuencia.

Pregunta de seguimiento 3: ¿Cómo se degrada para navegadores más antiguos?

Mantén un indicador de progreso estático y el contenido completo. Si el progreso dinámico es esencial, utiliza un listener de scroll con throttle para una pequeña actualización. La degradación no debe alterar el orden de lectura, el acceso por teclado ni el comportamiento del foco.

Pregunta de seguimiento 4: ¿Cómo se respeta el movimiento reducido?

Bajo prefers-reduced-motion: reduce, elimina traslaciones, escalados y movimientos prolongados. Mantén actualizaciones de progreso estáticas o instantáneas, el orden del contenido y una retroalimentación legible, y verifica que el desplazamiento rápido no oculte información.

Fuentes públicas

Preguntas relacionadas