Ir al contenido
AppsSDAR

Astro y transition:persist: el enlace que se quedó congelado

4 min de lectura Frontend y UX

Astro permite que un sitio estático se navegue sin recargas completas gracias a las View Transitions. Con la directiva transition:persist, un elemento como la barra superior se conserva entre páginas en vez de volver a dibujarse, lo que evita parpadeos y mantiene su estado. Es muy útil y tiene una consecuencia que no es evidente hasta que rompe algo.

El bug

El logo de este sitio enlaza a distintos destinos según la página. En la portada apunta al ancla #inicio, para volver arriba sin recargar. En cualquier otra página apunta a /. El valor se pasaba como prop al componente de la barra, que tenía transition:persist.

Al entrar por la portada y navegar a la página de términos, el logo seguía enlazando a #inicio. Resuelto contra la URL actual, eso llevaba a /terminos/#inicio, un ancla que no existe en esa página. Hacer clic en el logo no hacía nada.

Por qué pasa

Un elemento persistido no se vuelve a renderizar al navegar: se toma el nodo del DOM de la página anterior y se inserta tal cual en la nueva. Por lo tanto, todo lo que se calculó en el servidor para ese elemento queda congelado con los valores de la primera página donde se renderizó. Los props de la página nueva existen en su HTML, pero se descartan en favor del nodo persistido.

El mismo problema ya había aparecido antes con el estado visual: la sección activa de una barra lateral persistida quedaba marcada según la primera página visitada. Esta vez afectaba a contenido, un enlace, y por eso rompía la navegación.

La corrección

Todo valor de un elemento persistido que dependa de la página actual se recalcula en el navegador después de cada navegación. Astro emite el evento astro:page-load al terminar de cargar cada página, incluida la primera. En ese evento, el script lee la ruta actual y ajusta el enlace del logo y la marca de sección activa.

La regla práctica: nunca confiar en un valor renderizado en el servidor para un elemento que persiste entre navegaciones, si ese valor cambia de una página a otra.

Una trampa vecina: CSS con ámbito

Otra sorpresa de Astro, que ya causó el mismo bug dos veces en proyectos distintos. Los estilos escritos en un componente se limitan a ese componente agregando un atributo único a su marcado. Ese atributo solo se agrega a los elementos que el componente renderiza al compilar.

Si un script crea elementos después, por ejemplo al insertar la lista de archivos cargados, esos elementos no tienen el atributo y los estilos del componente no los alcanzan. El fallo es silencioso: el elemento cae al estilo por defecto del navegador y se ve raro, pero nada se rompe. Para contenido generado por JavaScript, las reglas deben declararse como globales, idealmente acotadas bajo un contenedor propio para no afectar al resto del sitio.

Lista de verificación

  • Revisar cada elemento con transition:persist y listar los props que dependen de la página.
  • Recalcular esos valores en astro:page-load.
  • Probar navegando entre páginas distintas, no solo recargando cada una.
  • En componentes que insertan HTML por JavaScript, verificar que sus estilos sean globales o usen el selector global.