next.jsanimationercss och layouter

View Transitions i Next.js: sidanimationer utan animationsbibliotek

View Transitions i Next.js: sidanimationer utan animationsbibliotek

View Transitions API tar det tricket från dig och ger det till webbläsaren. Istället för att hålla två levande DOM-träd och mäta dem fotograferar webbläsaren det gamla tillståndet, låter DOM uppdateras, fotograferar det nya tillståndet och animerar mellan de två bilderna – på compositorn.

javascript

function navigate(update) {
if (!document.startViewTransition) {
update(); // inget stöd: bara uppdatera, ingen animation
return;
}
document.startViewTransition(() => update());
}

css

::view-transition /* överlägget som täcker hela sidan */
::view-transition-group(name) /* animerar storlek och position */
::view-transition-image-pair(name)
::view-transition-old(name) /* "före"-ögonblicksbilden */
::view-transition-new(name) /* "efter"-ögonblicksbilden */

Det som förvånar alla: en ögonblicksbild är ett fotografi, inte ett element

::view-transition-old är inte ditt gamla element renderat mindre. Det är en statisk bild av det. En <video> fryser på en frame. En spinner slutar snurra. Vid 200ms spelar inget av det någon roll. Vid 1000ms blir allt uppenbart.

Namngivning: hela kontraktet

css

.card-image {
view-transition-name: hero;
}
::view-transition-group(hero) {
animation-duration: 400ms;
animation-timing-function: ease-in-out;
}

Den hårda regeln: ett view-transition-name måste vara unikt i dokumentet vid varje givet tillfälle.

React 19.2 och Next.js 16: en komponent

tsx

import { ViewTransition } from "react";
import Image from "next/image";
import Link from "next/link";
export function ProjectCard({ project }) {
return (
<Link href={"/projects/" + project.slug}>
<ViewTransition name={"project-" + project.slug}>
<Image src={project.cover} alt={project.title} />
</ViewTransition>
</Link>
);
}

share och default="none" måste följa med varandra. Med default="none" och ingen share-prop slutar det namngivna paret tyst att morpha.

Riktning: tala om för användaren åt vilket håll de gick

tsx

<Link href="/projects/runvalis" transitionTypes={["nav-forward"]}>
Runvalis
</Link>
<ViewTransition
enter={{ "nav-forward": "slide-in", "nav-back": "slide-out", default: "none" }}
exit={{ "nav-forward": "slide-out", "nav-back": "slide-in", default: "none" }}
default="none"
>
<main>{children}</main>
</ViewTransition>

Versionen utan något ramverk

css

@view-transition {
navigation: auto;
}

Fallgropar och bästa praxis

  • Behandla alltid som progressiv förbättring.
  • Felsök i slow motion.
  • Respektera prefers-reduced-motion.
  • Överlägget äter klick som standard.
  • Ögonblicksbilder kostar minne.
  • Förankra headern.
  • En view transition är osynlig för hjälpmedel.

Slutsats

View Transitions är samma argument tillämpad på navigering: istället för att köra FLIP för hand deklarerar du vad som förbinder två tillstånd och låter webbläsaren rita förbindelsen från två fotografier.