liquiddesign

Wzorzec 19

Przejście zamiast teleportacji

Po filtrowaniu listy użytkownik traci z oczu kartę, na którą patrzył, bo wszystko zmienia miejsce w jednej klatce. document.startViewTransition robi zrzut starego stanu, wprowadza nowy i animuje różnicę, a view-transition-name mówi przeglądarce, które elementy są tym samym bytem.

Filtruj i tasuj, nie gubiąc kart z oczu

Każda karta ma view-transition-name, więc przy zmianie kolejności płynie na nowe miejsce, zamiast teleportować się w jednej klatce. Filtrowanie wygasza znikające karty i wprowadza wracające.

Atlas

Branding

Heliotrop

Aplikacja

Novak

E-commerce

Wrzos

Branding

Akademia

Aplikacja

Magazyn

E-commerce

Siatka rezerwuje wysokość pełnego zestawu, więc filtrowanie nie rusza treści pod demo. Bez wsparcia przeglądarki i przy reduced motion ta sama funkcja aktualizuje stan natychmiast.

Reguły

  • Zmianę stanu opakowuje document.startViewTransition, reszta kodu zostaje bez zmian.
  • Każdy przenoszony element ma unikalny view-transition-name, więc płynie, zamiast znikać i wracać.
  • Brak wsparcia degraduje do natychmiastowej zmiany: ta sama funkcja aktualizuje stan z przejściem i bez.
  • prefers-reduced-motion pomija przejście i wprowadza nowy stan od razu.

Wzorzec w kodzie

Jedna funkcja obsługuje przejście, brak wsparcia i reduced motion
function withTransition(update: () => void) {
  const reducedMotion = matchMedia(
    "(prefers-reduced-motion: reduce)",
  ).matches;

  if (!document.startViewTransition || reducedMotion) {
    update();
    return;
  }
  document.startViewTransition(() => {
    flushSync(update);
  });
}
view-transition-name paruje stary i nowy zrzut: przeglądarka animuje różnicę pozycji i rozmiaru
<div style={{ viewTransitionName: `karta-${project.id}` }}>
  {project.name}
</div>