Wenn ein Ansichtsübergang für ein einzelnes Dokument ausgeführt wird, wird dies als Übergang für Ansichten im selben Dokument bezeichnet. Dies ist in der Regel bei Single-Page-Anwendungen (SPAs) der Fall, in denen JavaScript zur Aktualisierung des DOMs verwendet wird. Übergänge zwischen der Ansicht für das gleiche Dokument werden in Chrome ab Chrome 111 unterstützt.
Rufen Sie document.startViewTransition
auf, um einen Wechsel der Ansicht für dasselbe Dokument auszulösen:
function handleClick(e) {
// Fallback for browsers that don't support this API:
if (!document.startViewTransition) {
updateTheDOMSomehow();
return;
}
// With a View Transition:
document.startViewTransition(() => updateTheDOMSomehow());
}
Wenn der Browser aufgerufen wird, werden automatisch Snapshots aller Elemente erstellt, denen die CSS-Eigenschaft view-transition-name
deklariert wurde.
Anschließend führt es den übergebenen Callback aus, der das DOM aktualisiert und anschließend Snapshots des neuen Status erstellt.
Diese Momentaufnahmen werden dann in einer Baumstruktur aus Pseudoelementen angeordnet und mithilfe von CSS-Animationen animiert. Zwei Momentaufnahmen aus dem alten und neuen Zustand gehen nahtlos von ihrer alten Position und Größe an ihren neuen Ort über, während der Inhalt überblendet wird. Wenn Sie möchten, können Sie die Animationen mit CSS anpassen.
Standardübergang: Überblenden
Der Standardübergang der Ansicht ist ein Überblenden und dient als gute Einführung in die API:
function spaNavigate(data) {
// Fallback for browsers that don't support this API:
if (!document.startViewTransition) {
updateTheDOMSomehow(data);
return;
}
// With a transition:
document.startViewTransition(() => updateTheDOMSomehow(data));
}
Dabei ändert updateTheDOMSomehow
das DOM in den neuen Status. Das kann so gemacht werden, wie du es möchtest. Sie können beispielsweise Elemente hinzufügen oder entfernen, Klassennamen oder Stile ändern.
Und so funktioniert's:
<ph type="x-smartling-placeholder">Okay, eine Überblendung ist nicht so beeindruckend. Glücklicherweise können Übergänge angepasst werden, aber zuerst müssen Sie verstehen, wie diese grundlegende Überblendung funktioniert.
So funktionieren diese Umstellungen
Aktualisieren wir nun das vorherige Codebeispiel.
document.startViewTransition(() => updateTheDOMSomehow(data));
Wenn .startViewTransition()
aufgerufen wird, erfasst die API den aktuellen Status der Seite. Dazu gehört auch das Erstellen eines Snapshots.
Anschließend wird der an .startViewTransition()
übergebene Callback aufgerufen. Hier wird das DOM geändert. Anschließend erfasst die API den neuen Status der Seite.
Nachdem der neue Status erfasst wurde, erstellt die API einen Pseudoelementbaum wie folgt:
::view-transition
└─ ::view-transition-group(root)
└─ ::view-transition-image-pair(root)
├─ ::view-transition-old(root)
└─ ::view-transition-new(root)
::view-transition
wird in einem Overlay über allen anderen Elementen auf der Seite angezeigt. Dies ist nützlich, wenn Sie eine Hintergrundfarbe für den Übergang festlegen möchten.
::view-transition-old(root)
ist ein Screenshot der alten Ansicht und ::view-transition-new(root)
eine Live-Darstellung der neuen Ansicht. Beide werden als CSS-Inhalt „ersetzt“ gerendert (z. B. <img>
).
Die alte Ansicht wird von opacity: 1
bis opacity: 0
animiert, während die neue Ansicht von opacity: 0
zu opacity: 1
animiert, sodass eine Überblendung entsteht.
Die gesamte Animation wird mithilfe von CSS-Animationen durchgeführt, sodass sie mit CSS angepasst werden können.
Übergang anpassen
Für alle Pseudoelemente des Ansichtsübergangs kann mit CSS ein Targeting vorgenommen werden. Da die Animationen mit CSS definiert sind, können Sie sie mithilfe vorhandener CSS-Animationseigenschaften ändern. Beispiel:
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 5s;
}
Mit dieser einen Änderung wird das Ausblenden jetzt sehr langsam:
<ph type="x-smartling-placeholder">Okay, das ist immer noch nicht beeindruckend. Stattdessen wird mit dem folgenden Code der gemeinsame Achsenübergang in Material Design implementiert:
@keyframes fade-in {
from { opacity: 0; }
}
@keyframes fade-out {
to { opacity: 0; }
}
@keyframes slide-from-right {
from { transform: translateX(30px); }
}
@keyframes slide-to-left {
to { transform: translateX(-30px); }
}
::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
Und hier ist das Ergebnis:
<ph type="x-smartling-placeholder">Mehrere Elemente umstellen
In der vorherigen Demo ist die gesamte Seite am gemeinsamen Achsenübergang beteiligt. Das funktioniert für den Großteil der Seite, aber für die Überschrift scheint es nicht ganz richtig zu sein. Sie gleitet heraus, um wieder hineinzuschieben.
Um dies zu vermeiden, können Sie die Kopfzeile aus dem Rest der Seite extrahieren, sodass sie separat animiert werden kann. Dazu wird dem Element eine view-transition-name
zugewiesen.
.main-header {
view-transition-name: main-header;
}
Der Wert von view-transition-name
kann beliebig sein (außer für none
, d. h., es gibt keinen Übergangsnamen). Damit wird das Element während des Übergangs eindeutig identifiziert.
Das Ergebnis:
<ph type="x-smartling-placeholder">Jetzt bleibt die Kopfzeile an ihrer Position und wird überblenden.
Diese CSS-Deklaration hat dazu geführt, dass sich die Pseudoelementstruktur geändert hat:
::view-transition
├─ ::view-transition-group(root)
│ └─ ::view-transition-image-pair(root)
│ ├─ ::view-transition-old(root)
│ └─ ::view-transition-new(root)
└─ ::view-transition-group(main-header)
└─ ::view-transition-image-pair(main-header)
├─ ::view-transition-old(main-header)
└─ ::view-transition-new(main-header)
Es gibt jetzt zwei Übergangsgruppen. eines für die Überschrift und eines für den Rest. Sie können mit CSS ein unabhängiges Targeting sowie verschiedene Übergänge vornehmen. In diesem Fall wurde für main-header
jedoch der Standardübergang beibehalten, der eine Überblendung ist.
Okay, der Standardübergang ist nicht nur ein Überblenden, der ::view-transition-group
führt auch Übergänge aus:
- Position und Transformation (mit
transform
) - Breite
- Höhe
Das spielte bis jetzt keine Rolle, da der Header dieselbe Größe und Position auf beiden Seiten der DOM-Änderung hat. Sie können aber auch den Text in der Kopfzeile extrahieren:
.main-header-text {
view-transition-name: main-header-text;
width: fit-content;
}
fit-content
wird verwendet, damit das Element die Größe des Textes entspricht, anstatt sich auf die verbleibende Breite zu strecken. Andernfalls wird mit dem Zurückpfeil die Größe des Textelements für die Kopfzeile reduziert, anstatt auf beiden Seiten dasselbe Element zu verwenden.
Jetzt müssen wir mit drei Teilen spielen:
::view-transition
├─ ::view-transition-group(root)
│ └─ …
├─ ::view-transition-group(main-header)
│ └─ …
└─ ::view-transition-group(main-header-text)
└─ …
Auch hier die Standardeinstellungen:
<ph type="x-smartling-placeholder">Jetzt verschwindet der Überschriftentext etwas zufriedenstellend, um Platz für die Schaltfläche „Zurück“ zu schaffen.
Mit view-transition-class
mehrere Pseudoelemente auf die gleiche Weise animieren
Unterstützte Browser
- 125
- 125
- x
- x
Angenommen, Sie haben einen Übergang mit mehreren Karten, aber auch einen Titel auf der Seite. Um alle Karten mit Ausnahme des Titels zu animieren, müssen Sie einen Selektor schreiben, der auf jede einzelne Karte ausgerichtet ist.
h1 {
view-transition-name: title;
}
::view-transition-group(title) {
animation-timing-function: ease-in-out;
}
#card1 { view-transition-name: card1; }
#card2 { view-transition-name: card2; }
#card3 { view-transition-name: card3; }
#card4 { view-transition-name: card4; }
…
#card20 { view-transition-name: card20; }
::view-transition-group(card1),
::view-transition-group(card2),
::view-transition-group(card3),
::view-transition-group(card4),
…
::view-transition-group(card20) {
animation-timing-function: var(--bounce);
}
Du hast 20 Elemente? Das sind 20 Selektoren, die Sie schreiben müssen. Neues Element hinzufügen? Dann müssen Sie auch den Selektor erweitern, der die Animationsstile anwendet. Nicht ganz skalierbar.
Das view-transition-class
kann in den Pseudoelementen des Ansichtsübergangs verwendet werden, um dieselbe Stilregel anzuwenden.
#card1 { view-transition-name: card1; }
#card2 { view-transition-name: card2; }
#card3 { view-transition-name: card3; }
#card4 { view-transition-name: card4; }
#card5 { view-transition-name: card5; }
…
#card20 { view-transition-name: card20; }
#cards-wrapper > div {
view-transition-class: card;
}
html::view-transition-group(.card) {
animation-timing-function: var(--bounce);
}
Im folgenden Beispiel für Karten wird das vorherige CSS-Snippet verwendet. Auf alle Karten – auch neu hinzugefügte – wird mit einem Selektor dasselbe Timing angewendet: html::view-transition-group(.card)
.
Übergänge zur Fehlerbehebung
Da Ansichtsübergänge auf CSS-Animationen basieren, eignet sich der Bereich Animationen in den Chrome-Entwicklertools hervorragend für das Debugging von Übergängen.
Im Bereich Animationen können Sie die nächste Animation pausieren und dann mit dem Scrubbing-Menü vor- und zurückspringen. Die Übergangs-Pseudoelemente finden Sie im Steuerfeld Elemente.
<ph type="x-smartling-placeholder">Elemente mit Wechsel müssen nicht dasselbe DOM-Element sein
Bisher haben wir view-transition-name
verwendet, um separate Übergangselemente für den Titel und den Text in der Überschrift zu erstellen. Prinzipiell handelt es sich dabei um dasselbe Element vor und nach der DOM-Änderung. Sie können jedoch Übergänge erstellen, wenn dies nicht der Fall ist.
Beispielsweise kann die Hauptvideoeinbettung ein view-transition-name
erhalten:
.full-embed {
view-transition-name: full-embed;
}
Wenn dann auf das Thumbnail geklickt wird, kann es dasselbe view-transition-name
-Objekt erhalten, nur für die Dauer des Übergangs:
thumbnail.onclick = async () => {
thumbnail.style.viewTransitionName = 'full-embed';
document.startViewTransition(() => {
thumbnail.style.viewTransitionName = '';
updateTheDOMSomehow();
});
};
Und das Ergebnis:
<ph type="x-smartling-placeholder">Das Thumbnail geht nun zum Hauptbild über. Obwohl es sich um konzeptionell (und buchstäblich) unterschiedliche Elemente handelt, behandelt die Transition API sie als dasselbe, weil sie dieselbe view-transition-name
haben.
Der eigentliche Code für diesen Übergang ist etwas komplizierter als im vorherigen Beispiel, da er auch den Übergang zurück zur Thumbnail-Seite übernimmt. Die vollständige Implementierung finden Sie im Quellcode.
Benutzerdefinierte Einstiegs- und Exit-Übergänge
Sehen Sie sich dieses Beispiel an:
<ph type="x-smartling-placeholder">Die Seitenleiste ist Teil des Übergangs:
.sidebar {
view-transition-name: sidebar;
}
Im Gegensatz zur Kopfzeile im vorherigen Beispiel wird die Seitenleiste jedoch nicht auf allen Seiten angezeigt. Wenn beide Zustände die Seitenleiste haben, sehen die Übergangs-Pseudoelemente so aus:
::view-transition
├─ …other transition groups…
└─ ::view-transition-group(sidebar)
└─ ::view-transition-image-pair(sidebar)
├─ ::view-transition-old(sidebar)
└─ ::view-transition-new(sidebar)
Befindet sich die Seitenleiste jedoch nur auf der neuen Seite, ist das Pseudoelement ::view-transition-old(sidebar)
nicht vorhanden. Da es keine „alten“ Bild für die Seitenleiste hat das Bildpaar nur ein ::view-transition-new(sidebar)
. Befindet sich die Seitenleiste nur auf der alten Seite, hat das Bildpaar nur ein ::view-transition-old(sidebar)
.
In der vorherigen Demo werden die Übergänge der Seitenleiste unterschiedlich angepasst, je nachdem, ob sie in beiden Zuständen angezeigt wird, sie schließt oder sie verlässt. Sie wird eingeblendet, indem sie von rechts nach links gleitet und einblendet, sie wird durch das Gleiten nach rechts wieder weg und wieder ausgeblendet. Sie bleibt an ihrer Position, wenn sie in beiden Zuständen vorhanden ist.
Wenn Sie bestimmte Eingangs- und Exit-Übergänge erstellen möchten, können Sie die Pseudoklasse :only-child
verwenden, um ein Targeting auf die alten oder neuen Pseudoelemente vorzunehmen, wenn es das einzige untergeordnete Element im Bildpaar ist:
/* Entry transition */
::view-transition-new(sidebar):only-child {
animation: 300ms cubic-bezier(0, 0, 0.2, 1) both fade-in,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
/* Exit transition */
::view-transition-old(sidebar):only-child {
animation: 150ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-right;
}
In diesem Fall gibt es keinen spezifischen Übergang, wenn die Seitenleiste in beiden Status angezeigt wird, da die Standardeinstellung perfekt ist.
Asynchrone DOM-Updates und Warten auf Inhalte
Der an .startViewTransition()
übergebene Callback kann ein Promise zurückgeben, das asynchrone DOM-Aktualisierungen ermöglicht und darauf wartet, dass wichtige Inhalte bereit sind.
document.startViewTransition(async () => {
await something;
await updateTheDOMSomehow();
await somethingElse;
});
Die Umstellung wird erst gestartet, wenn das Versprechen erfüllt ist. Während dieser Zeit ist die Seite eingefroren, sodass die Verzögerungen auf ein Minimum begrenzt werden sollten. Insbesondere sollten Netzwerkabrufe vor dem Aufruf von .startViewTransition()
erfolgen, während die Seite noch vollständig interaktiv ist und nicht als Teil des .startViewTransition()
-Callbacks.
Wenn Sie warten möchten, bis Bilder oder Schriftarten bereitstehen, verwenden Sie ein aggressives Zeitlimit:
const wait = ms => new Promise(r => setTimeout(r, ms));
document.startViewTransition(async () => {
updateTheDOMSomehow();
// Pause for up to 100ms for fonts to be ready:
await Promise.race([document.fonts.ready, wait(100)]);
});
In manchen Fällen ist es jedoch besser, die Verzögerung ganz zu vermeiden und den bereits vorhandenen Content zu verwenden.
Bereits vorhandene Inhalte optimal nutzen
Wenn die Miniaturansicht zu einem größeren Bild übergeht:
<ph type="x-smartling-placeholder">Der Standardübergang ist Überblendung, d. h., die Miniaturansicht könnte überblenden mit einem noch nicht geladenen vollständigen Bild.
Sie können dies vermeiden, indem Sie warten, bis das vollständige Bild geladen ist, bevor Sie mit dem Übergang beginnen. Idealerweise sollte dies vor dem Aufruf von .startViewTransition()
erfolgen, damit die Seite interaktiv bleibt und ein rotierendes Ladesymbol eingeblendet wird, um den Nutzer darauf hinzuweisen, dass die Seite geladen wird. Aber in diesem Fall gibt es eine bessere Methode:
::view-transition-old(full-embed),
::view-transition-new(full-embed) {
/* Prevent the default animation,
so both views remain opacity:1 throughout the transition */
animation: none;
/* Use normal blending,
so the new view sits on top and obscures the old view */
mix-blend-mode: normal;
}
Jetzt verschwindet das Thumbnail nicht, sondern befindet sich nur unter dem vollständigen Bild. Wenn also die neue Ansicht nicht geladen wurde, ist die Miniaturansicht während des Übergangs zu sehen. Das bedeutet, dass der Übergang sofort beginnen kann und das vollständige Bild geladen werden kann.
Dies würde nicht funktionieren, wenn die neue Ansicht Transparenz beinhalten würde, aber in diesem Fall wissen wir, dass dies nicht der Fall ist, also können wir diese Optimierung vornehmen.
Mit Änderungen des Seitenverhältnisses umgehen
Praktischerweise erfolgten bisher alle Übergänge zu Elementen mit demselben Seitenverhältnis. Das wird jedoch nicht immer der Fall sein. Was ist, wenn das Thumbnail 1:1 und das Hauptbild 16:9 hat?
<ph type="x-smartling-placeholder">Beim Standardübergang wird die Gruppe von der Größe vor zur Nach-Größe animiert. Die alte und die neue Ansicht entsprechen der Breite der Gruppe und der automatischen Höhe beträgt 100 %. Das Seitenverhältnis wird also unabhängig von der Gruppengröße beibehalten.
Dies ist eine gute Standardeinstellung, aber nicht das, was in diesem Fall gewünscht wird. Das bedeutet:
::view-transition-old(full-embed),
::view-transition-new(full-embed) {
/* Prevent the default animation,
so both views remain opacity:1 throughout the transition */
animation: none;
/* Use normal blending,
so the new view sits on top and obscures the old view */
mix-blend-mode: normal;
/* Make the height the same as the group,
meaning the view size might not match its aspect-ratio. */
height: 100%;
/* Clip any overflow of the view */
overflow: clip;
}
/* The old view is the thumbnail */
::view-transition-old(full-embed) {
/* Maintain the aspect ratio of the view,
by shrinking it to fit within the bounds of the element */
object-fit: contain;
}
/* The new view is the full image */
::view-transition-new(full-embed) {
/* Maintain the aspect ratio of the view,
by growing it to cover the bounds of the element */
object-fit: cover;
}
Das bedeutet, dass die Miniaturansicht bei Vergrößerung der Breite in der Mitte des Elements bleibt, das vollständige Bild aber nicht zugeschnitten wird. wenn es von 1:1 zu 16:9 wechselt.
Weitere Informationen finden Sie unter Übergänge ansehen: Umgang mit Änderungen des Seitenverhältnisses.
Verwenden Sie Medienabfragen, um Übergänge für verschiedene Gerätestatus zu ändern
Sie können auf Mobilgeräten und Desktop-Computern andere Übergänge verwenden, wie in diesem Beispiel, in dem auf Mobilgeräten eine vollständige Folie von der Seite und auf Desktop-Computern eine subtilere Folie zu sehen ist:
<ph type="x-smartling-placeholder">Dies kann mithilfe regulärer Medienabfragen erreicht werden:
/* Transitions for mobile */
::view-transition-old(root) {
animation: 300ms ease-out both full-slide-to-left;
}
::view-transition-new(root) {
animation: 300ms ease-out both full-slide-from-right;
}
@media (min-width: 500px) {
/* Overrides for larger displays.
This is the shared axis transition from earlier in the article. */
::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
}
Sie können auch ändern, welche Elemente Sie je nach übereinstimmenden Medienabfragen eine view-transition-name
zuweisen.
Auf „verringerte Bewegungen“ reagieren Einstellung
Nutzer können angeben, dass sie Bewegungen in ihrem Betriebssystem reduzieren möchten. Diese Präferenz wird in CSS angezeigt.
Sie können Umstellungen für diese Nutzer verhindern:
@media (prefers-reduced-motion) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
Eine Präferenz für „verringerte Bewegungen“ bedeutet nicht, dass der Nutzer keine Bewegung haben möchte. Anstelle des vorhergehenden Snippets könnten Sie eine subtilere Animation wählen, die aber dennoch die Beziehung zwischen den Elementen und den Datenfluss zum Ausdruck bringt.
Mehrere Ansichtsübergangsstile mit Ansichtsübergangstypen verarbeiten
Unterstützte Browser
- 125
- 125
- x
- x
Manchmal sollte ein Wechsel von einer bestimmten Ansicht zur anderen genau angepasst werden. Wenn Sie beispielsweise mit einer Paginierung zur nächsten oder vorherigen Seite wechseln, können Sie den Inhalt in eine andere Richtung verschieben, je nachdem, ob Sie zu einer höheren oder einer niedrigeren Seite aus der Abfolge springen.
<ph type="x-smartling-placeholder">Dazu können Sie Arten von Ansichtenübergangen verwenden, mit denen Sie einem Active View-Übergang einen oder mehrere Typen zuweisen können. Wenn Sie beispielsweise bei einer Paginierungssequenz zu einer höheren Seite übergehen, verwenden Sie den Typ forwards
und beim Wechsel zu einer niedrigeren Seite den Typ backwards
. Diese Typen sind nur aktiv, wenn ein Übergang erfasst oder ausgeführt wird. Jeder Typ kann über CSS angepasst werden, um verschiedene Animationen zu verwenden.
Wenn Sie bei einem Übergang der Ansicht für dasselbe Dokument Typen verwenden möchten, übergeben Sie types
an die startViewTransition
-Methode. Dazu akzeptiert document.startViewTransition
auch ein Objekt: update
ist die Callback-Funktion, die das DOM aktualisiert, und types
ist ein Array mit den Typen.
const direction = determineBackwardsOrForwards();
const t = document.startViewTransition({
update: updateTheDOMSomehow,
types: ['slide', direction],
});
Verwenden Sie den Selektor :active-view-transition-type()
, um auf diese Typen zu reagieren. Übergeben Sie den type
, auf den Sie ein Targeting vornehmen möchten, in den Selektor. Auf diese Weise können Sie die Stile mehrerer Ansichtsübergänge voneinander getrennt halten, ohne dass die Deklarationen des einen Übergangs die Deklarationen des anderen beeinflussen.
Da Typen nur beim Erfassen oder Ausführen des Übergangs angewendet werden, können Sie mit dem Selektor eine view-transition-name
für ein Element nur für den Ansichtsübergang mit diesem Typ festlegen oder aufheben.
/* Determine what gets captured when the type is forwards or backwards */
html:active-view-transition-type(forwards, backwards) {
:root {
view-transition-name: none;
}
article {
view-transition-name: content;
}
.pagination {
view-transition-name: pagination;
}
}
/* Animation styles for forwards type only */
html:active-view-transition-type(forwards) {
&::view-transition-old(content) {
animation-name: slide-out-to-left;
}
&::view-transition-new(content) {
animation-name: slide-in-from-right;
}
}
/* Animation styles for backwards type only */
html:active-view-transition-type(backwards) {
&::view-transition-old(content) {
animation-name: slide-out-to-right;
}
&::view-transition-new(content) {
animation-name: slide-in-from-left;
}
}
/* Animation styles for reload type only (using the default root snapshot) */
html:active-view-transition-type(reload) {
&::view-transition-old(root) {
animation-name: fade-out, scale-down;
}
&::view-transition-new(root) {
animation-delay: 0.25s;
animation-name: fade-in, scale-up;
}
}
In der folgenden Demo zur Paginierung wird der Seiteninhalt je nach Seitennummer, die Sie aufrufen, vor- oder zurückgeschoben. Die Typen werden durch einen Klick festgelegt und nach dem Klick an document.startViewTransition
übergeben.
Für das Targeting auf alle Active View-Übergänge unabhängig vom Typ können Sie stattdessen den Pseudoklassenselektor :active-view-transition
verwenden.
html:active-view-transition {
…
}
Mehrere Stilübergangsstile für Ansichten mit einem Klassennamen im Stamm des Ansichtsübergangs verarbeiten
Manchmal sollte ein Übergang von einem bestimmten Ansichtstyp zu einem anderen genau angepasst werden. oder „Zurück“ Navigation sollte sich von "forward" unterscheiden. Navigation.
<ph type="x-smartling-placeholder">Vor den Übergangstypen wurde für diese Fälle vorübergehend ein Klassenname im Übergangsstamm festgelegt. Beim Aufrufen von document.startViewTransition
ist dieser Übergangsstamm das <html>
-Element, auf das mit document.documentElement
in JavaScript zugegriffen werden kann:
if (isBackNavigation) {
document.documentElement.classList.add('back-transition');
}
const transition = document.startViewTransition(() =>
updateTheDOMSomehow(data)
);
try {
await transition.finished;
} finally {
document.documentElement.classList.remove('back-transition');
}
In diesem Beispiel wird transition.finished
verwendet, um die Klassen nach Abschluss des Übergangs zu entfernen. Dieses Promise wird aufgelöst, sobald der Übergang den Endzustand erreicht hat. Weitere Eigenschaften dieses Objekts werden in der API-Referenz behandelt.
Jetzt können Sie diesen Klassennamen in Ihrem CSS-Code verwenden, um den Übergang zu ändern:
/* 'Forward' transitions */
::view-transition-old(root) {
animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}
::view-transition-new(root) {
animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in, 300ms
cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
}
/* Overrides for 'back' transitions */
.back-transition::view-transition-old(root) {
animation-name: fade-out, slide-to-right;
}
.back-transition::view-transition-new(root) {
animation-name: fade-in, slide-from-left;
}
Wie bei Medienabfragen könnte das Vorhandensein dieser Klassen auch verwendet werden, um zu ändern, welche Elemente eine view-transition-name
erhalten.
Übergänge ausführen, ohne andere Animationen einzufrieren
Sehen Sie sich diese Demo für eine Videoübergangsposition an:
<ph type="x-smartling-placeholder">Gab es ein Problem damit? Keine Sorge, wenn Sie das nicht getan haben. Hier ist es verlangsamt:
<ph type="x-smartling-placeholder">Während des Übergangs scheint das Video einzufrieren, dann wird die wiedergegebene Version des Videos eingeblendet. Das liegt daran, dass ::view-transition-old(video)
ein Screenshot der alten Ansicht ist, während ::view-transition-new(video)
ein Live-Bild der neuen Ansicht ist.
Sie können das Problem beheben. Fragen Sie sich jedoch zuerst, ob sich eine Fehlerbehebung lohnt. Wenn Sie „Problem“ nicht gesehen haben wenn der Übergang in normaler Geschwindigkeit abgespielt wird, würde ich ihn nicht ändern.
Wenn du das Problem wirklich beheben möchtest, zeig den ::view-transition-old(video)
nicht an. wechseln Sie direkt zu ::view-transition-new(video)
. Dazu können Sie die Standardstile und -animationen überschreiben:
::view-transition-old(video) {
/* Don't show the frozen old view */
display: none;
}
::view-transition-new(video) {
/* Don't fade the new view in */
animation: none;
}
Webseite.
<ph type="x-smartling-placeholder">Das Video wird jetzt während des Übergangs abgespielt.
Animationen mit JavaScript
Bisher wurden alle Übergänge mit CSS definiert, aber manchmal reicht CSS nicht aus:
<ph type="x-smartling-placeholder">Einige Teile dieser Umstellung können mit CSS allein nicht erreicht werden:
- Die Animation beginnt an der Klickposition.
- Die Animation endet damit, dass der Kreis einen Radius zur längsten Ecke hat. Allerdings wird dies hoffentlich in der Zukunft mit Preisvergleichsportalen möglich sein.
Glücklicherweise können Sie Übergänge mit der Web Animation API erstellen.
let lastClick;
addEventListener('click', event => (lastClick = event));
function spaNavigate(data) {
// Fallback for browsers that don't support this API:
if (!document.startViewTransition) {
updateTheDOMSomehow(data);
return;
}
// Get the click position, or fallback to the middle of the screen
const x = lastClick?.clientX ?? innerWidth / 2;
const y = lastClick?.clientY ?? innerHeight / 2;
// Get the distance to the furthest corner
const endRadius = Math.hypot(
Math.max(x, innerWidth - x),
Math.max(y, innerHeight - y)
);
// With a transition:
const transition = document.startViewTransition(() => {
updateTheDOMSomehow(data);
});
// Wait for the pseudo-elements to be created:
transition.ready.then(() => {
// Animate the root's new view
document.documentElement.animate(
{
clipPath: [
`circle(0 at ${x}px ${y}px)`,
`circle(${endRadius}px at ${x}px ${y}px)`,
],
},
{
duration: 500,
easing: 'ease-in',
// Specify which pseudo-element to animate
pseudoElement: '::view-transition-new(root)',
}
);
});
}
In diesem Beispiel wird transition.ready
verwendet, ein Promise, das aufgelöst wird, sobald die Übergangs-Pseudoelemente erfolgreich erstellt wurden. Weitere Eigenschaften dieses Objekts werden in der API-Referenz behandelt.
Übergänge als Erweiterung
Die View Transition API ist so konzipiert, eine DOM-Änderung erstellen und einen Übergang dafür erstellen. Der Übergang sollte jedoch als Verbesserung behandelt werden, da Ihre App keinen Fehler eingeben sollte. wenn die DOM-Änderung erfolgreich war, aber der Übergang fehlschlägt. Im Idealfall sollte die Umstellung nicht fehlschlagen, aber falls doch, sollte sie die restliche Nutzererfahrung nicht beeinträchtigen.
Achte darauf, Übergangsversprechen nicht so zu verwenden, dass deine App bei einem Fehler eine Ausgabe auslöst.
async function switchView(data) { // Fallback for browsers that don't support this API: if (!document.startViewTransition) { await updateTheDOM(data); return; } const transition = document.startViewTransition(async () => { await updateTheDOM(data); }); await transition.ready; document.documentElement.animate( { clipPath: [`inset(50%)`, `inset(0)`], }, { duration: 500, easing: 'ease-in', pseudoElement: '::view-transition-new(root)', } ); }
Das Problem bei diesem Beispiel ist, dass switchView()
abgelehnt wird, wenn der Übergang den Status ready
nicht erreichen kann. Das bedeutet aber nicht, dass die Ansicht nicht gewechselt werden konnte. Das DOM wurde möglicherweise erfolgreich aktualisiert, aber es gab doppelte view-transition-name
s, sodass der Übergang übersprungen wurde.
Gehen Sie in diesem Fall so vor:
async function switchView(data) { // Fallback for browsers that don't support this API: if (!document.startViewTransition) { await updateTheDOM(data); return; } const transition = document.startViewTransition(async () => { await updateTheDOM(data); }); animateFromMiddle(transition); await transition.updateCallbackDone; } async function animateFromMiddle(transition) { try { await transition.ready; document.documentElement.animate( { clipPath: [`inset(50%)`, `inset(0)`], }, { duration: 500, easing: 'ease-in', pseudoElement: '::view-transition-new(root)', } ); } catch (err) { // You might want to log this error, but it shouldn't break the app } }
In diesem Beispiel wird transition.updateCallbackDone
verwendet, um auf die DOM-Aktualisierung zu warten und sie abzulehnen, wenn sie fehlschlägt. switchView
lehnt nicht mehr ab, wenn der Übergang fehlschlägt, wird aufgelöst, wenn die DOM-Aktualisierung abgeschlossen ist, und lehnt sie ab, wenn die Umstellung fehlschlägt.
Wenn switchView
nach Abschluss der neuen Ansicht aufgelöst werden soll, z. B. wenn ein animierter Übergang abgeschlossen oder bis zum Ende übersprungen wurde, ersetzen Sie transition.updateCallbackDone
durch transition.finished
.
Kein Polyfill, aber...
Dies ist keine einfache Funktion für Polyfills. Diese Hilfsfunktion vereinfacht jedoch die Verwendung in Browsern, die keine Ansichtsübergänge unterstützen:
function transitionHelper({
skipTransition = false,
types = [],
update,
}) {
const unsupported = (error) => {
const updateCallbackDone = Promise.resolve(update()).then(() => {});
return {
ready: Promise.reject(Error(error)),
updateCallbackDone,
finished: updateCallbackDone,
skipTransition: () => {},
types,
};
}
if (skipTransition || !document.startViewTransition) {
return unsupported('View Transitions are not supported in this browser');
}
try {
const transition = document.startViewTransition({
update,
types,
});
return transition;
} catch (e) {
return unsupported('View Transitions with types are not supported in this browser');
}
}
Und es kann so verwendet werden:
function spaNavigate(data) {
const types = isBackNavigation ? ['back-transition'] : [];
const transition = transitionHelper({
update() {
updateTheDOMSomehow(data);
},
types,
});
// …
}
In Browsern, die keine Wechselübergänge unterstützen, wird updateDOM
zwar aufgerufen, es erfolgt jedoch kein animierter Übergang.
Du kannst während des Übergangs auch einige classNames
hinzufügen, die zu <html>
hinzugefügt werden können. Dadurch wird es einfacher, den Übergang je nach Art der Navigation zu ändern.
Sie können auch in Browsern, die Ansichtsübergänge unterstützen, auch true
an skipTransition
übergeben, wenn Sie keine Animation verwenden möchten. Dies ist nützlich, wenn Ihre Website eine Nutzereinstellung zum Deaktivieren von Übergängen hat.
Mit Frameworks arbeiten
Wenn Sie mit einer Bibliothek oder einem Framework arbeiten, das DOM-Änderungen abstrahiert, ist der schwierige Teil zu wissen, wann die DOM-Änderung abgeschlossen ist. Hier ist eine Reihe von Beispielen, für die der Helper oben in verschiedenen Frameworks verwendet wird.
- React (Reagieren): Der Schlüssel ist
flushSync
, mit dem eine Reihe von Statusänderungen synchron angewendet wird. Ja, es gibt eine Warnung vor der Verwendung dieser API, aber Dan Abramov versichert, dass es in diesem Fall angemessen ist. Wie bei React und asynchronem Code auch bei der Verwendung der verschiedenen vonstartViewTransition
zurückgegebenen Promis muss darauf geachtet werden, dass der Code mit dem richtigen Status ausgeführt wird. - Vue.js: Der Schlüssel ist
nextTick
. Er wird ausgeführt, sobald das DOM aktualisiert wurde. - Svelte: sehr ähnlich wie Vue, aber mit der Methode zum Warten auf die nächste Änderung wird
tick
verwendet. - Liegen – hier ist das Promise
this.updateComplete
innerhalb der Komponenten, das erfüllt wird, sobald das DOM aktualisiert wurde. - Angular: Der Schlüssel hier ist
applicationRef.tick
. Damit werden ausstehende DOM-Änderungen geleert. Ab der Angular-Version 17 kannst duwithViewTransitions
verwenden, die im@angular/router
enthalten ist.
API-Referenz
const viewTransition = document.startViewTransition(update)
Neue
ViewTransition
starten.update
ist eine Funktion, die aufgerufen wird, sobald der aktuelle Status des Dokuments erfasst wurde.Wenn dann das von
updateCallback
zurückgegebene Versprechen erfüllt wird, beginnt der Übergang im nächsten Frame. Wenn das vonupdateCallback
zurückgegebene Promise abgelehnt wird, wird der Übergang abgebrochen.const viewTransition = document.startViewTransition({ update, types })
Neue
ViewTransition
mit den angegebenen Typen startenupdate
wird aufgerufen, sobald der aktuelle Status des Dokuments erfasst wurde.Mit
types
werden die aktiven Typen für den Übergang beim Erfassen oder Ausführen des Übergangs festgelegt. Anfangs ist es leer. Weitere Informationen findest du unter „viewTransition.types
“ weiter unten.
Instanzmitglieder von ViewTransition
:
viewTransition.updateCallbackDone
Ein Versprechen, das erfüllt wird, wenn das von
updateCallback
zurückgegebene Versprechen erfüllt oder abgelehnt wird, wenn es abgelehnt wird.Die View Transition API schließt eine DOM-Änderung ein und erstellt einen Übergang. Manchmal ist der Erfolg oder Misserfolg der Übergangsanimation für Sie jedoch irrelevant, sondern Sie möchten nur wissen, ob und wann die DOM-Änderung erfolgt.
updateCallbackDone
ist für diesen Anwendungsfall geeignet.viewTransition.ready
Ein Versprechen, das erfüllt wird, sobald die Pseudoelemente für den Übergang erstellt wurden und die Animation gleich beginnt.
Wird abgelehnt, wenn der Übergang nicht beginnen kann. Das kann an einer fehlerhaften Konfiguration liegen, z. B. an doppelten
view-transition-name
s, oder wennupdateCallback
ein abgelehntes Promise zurückgibt.Dies ist nützlich, um die Übergangs-Pseudoelemente mit JavaScript zu animieren.
viewTransition.finished
Ein Versprechen, das erfüllt wird, sobald der Endzustand für den Nutzer vollständig sichtbar und interaktiv ist.
Es wird nur abgelehnt, wenn
updateCallback
ein abgelehntes Promise zurückgibt, da dies darauf hinweist, dass der Endstatus nicht erstellt wurde.Wenn ein Übergang nicht beginnt oder während des Übergangs übersprungen wird, ist der Endzustand trotzdem erreicht, sodass
finished
ausgeführt wird.viewTransition.types
Ein
Set
-ähnliches Objekt, das die Typen des Active View-Übergangs enthält. Verwenden Sie zum Bearbeiten der Einträge die Instanzmethodenclear()
,add()
unddelete()
.Um auf einen bestimmten Typ in CSS zu reagieren, verwenden Sie den Pseudoklassenselektor
:active-view-transition-type(type)
im Übergangsstamm.Typen werden automatisch bereinigt, wenn der Ansichtsübergang abgeschlossen ist.
viewTransition.skipTransition()
Animationsteil des Übergangs überspringen.
Dadurch wird der Aufruf von
updateCallback
nicht übersprungen, da die DOM-Änderung vom Übergang getrennt ist.
Referenz für Standardstil und Übergang
::view-transition
- Das Stamm-Pseudoelement, das den Darstellungsbereich ausfüllt und alle
::view-transition-group
enthält. ::view-transition-group
Absolut positioniert.
Übergänge
width
undheight
zwischen "Vorher" und „nachher“ Bundesländer.Übergänge
transform
zwischen "Vorher" und „nachher“ Darstellungsbereich-Quad.::view-transition-image-pair
Für diese Gruppe ist absolut bestens gerüstet.
Hat
isolation: isolate
, um die Auswirkungen vonmix-blend-mode
auf die alte und die neue Datenansicht zu begrenzen.::view-transition-new
und::view-transition-old
Absolute Position links oben im Wrapper.
Füllt 100% der Gruppenbreite aus, aber die Höhe wird automatisch festgelegt, sodass das Seitenverhältnis beibehalten wird und die Gruppe nicht überfüllt wird.
Enthält
mix-blend-mode: plus-lighter
, um eine echte Überblendung zu ermöglichen.Die alte Ansicht wird von
opacity: 1
aufopacity: 0
umgestellt. Die neue Ansicht wechselt vonopacity: 0
zuopacity: 1
.
Feedback
Wir freuen uns immer über Feedback von Entwicklern. Melden Sie dazu ein Problem bei der CSS Working Group auf GitHub und fügen Sie Vorschläge und Fragen hinzu. Stellen Sie dem Problem [css-view-transitions]
voran.
Sollten Sie auf einen Fehler stoßen, melden Sie den Fehler in Chromium.