React

View transitions in Astro: cosa persiste e cosa si ricarica

Il router di Astro sostituisce il body a ogni navigazione, quindi gli script ripartono. transition:persist e page-load risolvono quasi tutti i casi.

In sintesi

  • ClientRouter intercetta i link interni e sostituisce il body a ogni navigazione.
  • transition:persist conserva il nodo DOM, non lo stato JavaScript.
  • astro:page-load è l’evento da usare al posto di DOMContentLoaded.

Le view transitions in Astro si attivano con <ClientRouter /> nel layout: da quel momento ogni link interno viene intercettato, il body viene sostituito e il browser anima il cambio. Il costo è che nulla resta montato se non lo dichiari.

Attivare il router

---
import { ClientRouter } from "astro:transitions";
---

  
    
  
  

Fino ad Astro 4 il componente si chiamava ViewTransitions. Il nome nuovo dice cosa fa: non si limita all’API del browser, la sostituisce con un router lato client.

Cosa sopravvive alla navigazione

ElementoComportamento predefinitoDirettiva
Isola interattivaSi smonta e si rimontaNessuna
Player audioSi interrompetransition:persist
Modale apertaSi chiudetransition:persist
Script inlineRieseguito a ogni paginaastro:page-load

Un nome condiviso per l’animazione

---
const { posts } = Astro.props;
---

{posts.map((post) => (
  
    
  
))}

transition:name connette due elementi che rappresentano la stessa cosa in pagine diverse: il browser anima posizione e dimensione fra i due. Il nome deve essere unico sia nella pagina di partenza sia in quella di arrivo, quindi include l’id del post e non la parola cover.

Senza transition:name il router anima comunque il body intero con una dissolvenza: quella è l’animazione predefinita, e transition:animate la sostituisce quando serve un movimento diverso.

Persistere un elemento

transition:persist conserva il nodo DOM quando l’elemento compare nella pagina nuova con la stessa identità. Di default un’isola persistita riceve le props nuove; transition:persist-props conserva quelle del primo render.

Inizializzare dopo ogni navigazione

document.addEventListener("astro:page-load", () => {
  document.querySelectorAll("[data-reveal]").forEach((el) => {
    el.classList.add("is-visible");
  });
});

Un listener su DOMContentLoaded gira una volta sola: dopo la prima navigazione non viene più chiamato. L’evento giusto è astro:page-load, che arriva anche al primo caricamento.

Quando rompere l’intercettazione

  • Link verso un’altra origine: nessuna intercettazione, navigazione normale.
  • Download o PDF: aggiungi data-astro-reload per un caricamento pieno.
  • Form con POST: non passa dal router, la pagina si ricarica.
  • Dare lo stesso transition:name a due immagini della stessa pagina: l’animazione parte dall’elemento sbagliato.

Il limite noto

Il router sostituisce il body, non lo stato JavaScript. Un contatore dentro un modulo ES riparte da zero a ogni navigazione, anche con transition:persist: la persistenza riguarda il DOM, non le variabili. Se lo stato deve vivere tra le pagine, mettilo in un archivio esplicito o in sessionStorage.

La regola di decisione

Regola: aggiungi il router quando la navigazione è frequente e la testata resta identica fra le pagine; su un sito di tre pagine i 38,0 KB non si ripagano e il caricamento pieno è più prevedibile. Il secondo criterio è lo stato: se la pagina successiva deve ricordare quello che l’utente ha fatto, il router non basta.

Il costo si paga anche in debugging: un evento legato a window sopravvive alla navigazione, un listener su un nodo no, e la differenza si vede solo dopo il secondo click. Tieni un solo punto di inizializzazione e richiamalo da astro:page-load.

Il router emette quattro eventi oltre a astro:page-load: astro:before-preparation, astro:after-preparation, astro:before-swap e astro:after-swap. Servono a leggere l’URL in arrivo prima che il DOM cambi e a rimettere a posto un elemento dopo lo scambio, senza aspettare che la pagina nuova sia pronta.

Comandi

npx astro check
npx astro build

Dal catalogo: viewfinder flip carousel, il blocco logo Astro e saastro. Le guide: le content collections e la direttiva client mancante; il confronto: Astro contro Next.js sulla documentazione.

Domande frequenti

Devo cambiare i miei link?

No. Il router intercetta i link interni che trova nel documento: basta che siano anchor normali con href.

Perché lo script non parte più dopo la prima pagina?

Perché l’evento DOMContentLoaded non si ripete. Sposta l’inizializzazione su astro:page-load.

Le view transitions funzionano su Safari e Firefox?

Sì, con gradi diversi di supporto dell’API del browser. Quando manca, Astro naviga normalmente senza animazione.

Come disattivo le animazioni?

Rimuovi ClientRouter dal layout e torni alla navigazione classica. Per un solo link usa l’attributo data-astro-reload.

Posso usarle con le isole React?

Sì. L’isola si smonta e si rimonta a ogni navigazione, a meno che tu non usi transition:persist sull’elemento che la contiene.