Wenn ein Ansichtsübergang zwischen zwei verschiedenen Dokumenten stattfindet, wird dies als dokumentübergreifender Ansichtsübergang bezeichnet. Dies ist in der Regel bei mehrseitigen Anwendungen (MPA) der Fall. Die Umstellung der Ansicht dokumentübergreifend wird in Chrome ab Chrome 126 unterstützt.
Übergänge für die dokumentübergreifende Ansicht basieren auf denselben Bausteinen und Prinzipien wie Übergänge für die gleiche Dokumentansicht, was sehr beabsichtigt ist:
- Der Browser erstellt Momentaufnahmen von Elementen, die sowohl auf der alten als auch auf der neuen Seite eine eindeutige
view-transition-name
haben. - Das DOM wird aktualisiert, während das Rendering unterdrückt wird.
- Und schließlich werden die Übergänge von CSS-Animationen unterstützt.
Der Unterschied zu Übergängen der Ansicht desselben Dokuments besteht darin, dass Sie bei dokumentenübergreifenden Ansichtsübergängen nicht document.startViewTransition
aufrufen müssen, um einen Übergang der Ansicht zu starten. Der Trigger für einen dokumentenübergreifenden Ansichtsübergang ist stattdessen die Navigation am selben Ursprung von einer Seite zur anderen. Diese Aktion wird in der Regel dadurch ausgeführt, dass der Nutzer Ihrer Website auf einen Link klickt.
Mit anderen Worten: Es muss keine API aufgerufen werden, um einen Ansichtsübergang zwischen zwei Dokumenten zu starten. Es gibt jedoch zwei Bedingungen, die erfüllt sein müssen:
- Beide Dokumente müssen aus demselben Ursprung bestehen.
- Für beide Seiten muss die Option aktiviert werden, um den Ansichtsübergang zu ermöglichen.
Beide Bedingungen werden weiter unten in diesem Dokument erläutert.
Dokumentübergreifende Ansichtsübergänge sind auf Navigationen am selben Ursprung beschränkt
Dokumentübergreifende Ansichtsübergänge sind auf Navigationen am selben Ursprung beschränkt. Eine Navigation gilt als von derselben Quelle, wenn der Ursprung beider teilnehmenden Seiten derselbe ist.
Der Ursprung einer Seite ist eine Kombination aus dem verwendeten Schema, Hostnamen und Port, wie unter web.dev beschrieben.
So können Sie z. B. beim Navigieren von developer.chrome.com
zu developer.chrome.com/blog
einen dokumentenübergreifenden Ansichtsübergang haben, da diese Elemente denselben Ursprung haben.
Dieser Übergang ist beim Navigieren von developer.chrome.com
zu www.chrome.com
nicht möglich, da es sich um ursprungsübergreifend und Website derselben Website handelt.
Wechsel zu dokumentübergreifender Ansicht nur optional
Um einen dokumentenübergreifenden Ansichtsübergang zwischen zwei Dokumenten zu ermöglichen, müssen beide teilnehmenden Seiten dies zulassen. Dies geschieht mit der At-Regel @view-transition
in CSS.
Setze in der @view-transition
-at-Regel den navigation
-Deskriptor auf auto
, um Ansichtsübergänge für dokumentenübergreifende Navigationen am selben Ursprung zu aktivieren.
@view-transition {
navigation: auto;
}
Wenn Sie den navigation
-Deskriptor auf auto
setzen, werden Aufrufübergänge für die folgenden NavigationType-Elemente zugelassen:
traverse
push
oderreplace
, wenn die Aktivierung nicht vom Nutzer über die Benutzeroberfläche des Browsers initiiert wurde.
Von auto
ausgeschlossene Navigationen sind z. B. das Navigieren über die URL-Adressleiste oder das Klicken auf ein Lesezeichen sowie jede Form von Nutzer- oder Skriptaktualisierung.
Wenn eine Navigation zu lange dauert – in Chrome mehr als vier Sekunden – wird der Ansichtsübergang mit einem TimeoutError
-DOMException
übersprungen.
Demo zu dokumentenübergreifenden Umstellungen
In der folgenden Demo werden Ansichtsübergänge verwendet, um eine Stack Navigator-Demo zu erstellen. Hier sind keine document.startViewTransition()
-Aufrufe vorhanden. Die Ansichtsumstellungen werden durch das Wechseln von einer Seite zur anderen ausgelöst.
Übergänge für dokumentübergreifende Ansicht anpassen
Zum Anpassen der dokumentübergreifenden Ansichtsübergänge gibt es einige Webplattformfunktionen, die Sie verwenden können.
- Die Ereignisse
pageswap
undpagereveal
- Informationen zur Aktivierung der Navigation
- Blockierung des Renderings
Diese Funktionen sind nicht Teil der View Transition API-Spezifikation selbst, wurden aber für die Verwendung in Verbindung mit dieser API entwickelt.
Die Ereignisse pageswap
und pagereveal
Damit Sie dokumentübergreifende Ansichtsübergänge anpassen können, enthält die HTML-Spezifikation zwei neue Ereignisse, die Sie verwenden können: pageswap
und pagereveal
.
Diese beiden Ereignisse werden für jede dokumentübergreifende Navigation desselben Ursprungs ausgelöst, unabhängig davon, ob ein Ansichtsübergang bevorsteht oder nicht. Wenn ein Ansichtswechsel zwischen den beiden Seiten stattfinden soll, können Sie bei diesen Ereignissen mithilfe der viewTransition
-Eigenschaft auf das ViewTransition
-Objekt zugreifen.
- Das
pageswap
-Ereignis wird ausgelöst, bevor der letzte Frame einer Seite gerendert wird. Damit können Sie in letzter Minute einige Änderungen auf der ausgehenden Seite vornehmen, bevor die alten Snapshots erstellt werden. - Das
pagereveal
-Ereignis wird auf einer Seite ausgelöst, nachdem sie initialisiert oder reaktiviert wurde, aber vor der ersten Renderingmöglichkeit. Damit können Sie die neue Seite anpassen, bevor die neuen Momentaufnahmen erstellt werden.
Sie können diese Ereignisse beispielsweise verwenden, um schnell einige view-transition-name
-Werte festzulegen oder zu ändern oder Daten von einem Dokument in ein anderes zu übergeben, indem Sie Daten aus sessionStorage
schreiben und lesen, um den Ansichtsübergang anzupassen, bevor das Dokument tatsächlich ausgeführt wird.
let lastClickX, lastClickY;
document.addEventListener('click', (event) => {
if (event.target.tagName.toLowerCase() === 'a') return;
lastClickX = event.clientX;
lastClickY = event.clientY;
});
// Write position to storage on old page
window.addEventListener('pageswap', (event) => {
if (event.viewTransition && lastClick) {
sessionStorage.setItem('lastClickX', lastClickX);
sessionStorage.setItem('lastClickY', lastClickY);
}
});
// Read position from storage on new page
window.addEventListener('pagereveal', (event) => {
if (event.viewTransition) {
lastClickX = sessionStorage.getItem('lastClickX');
lastClickY = sessionStorage.getItem('lastClickY');
}
});
Wenn Sie möchten, können Sie den Übergang bei beiden Ereignissen überspringen.
window.addEventListener("pagereveal", async (e) => {
if (e.viewTransition) {
if (goodReasonToSkipTheViewTransition()) {
e.viewTransition.skipTransition();
}
}
}
Das ViewTransition
-Objekt in pageswap
und pagereveal
ist zwei verschiedene Objekte. Außerdem behandeln sie die verschiedenen Promise unterschiedlich:
pageswap
: Sobald das Dokument ausgeblendet ist, wird das alteViewTransition
-Objekt übersprungen. In diesem Fall lehntviewTransition.ready
die Anfrage ab undviewTransition.finished
hat die Lösung.pagereveal
: Das PromiseupdateCallBack
ist an diesem Punkt bereits aufgelöst. Du kannst die PromiseviewTransition.ready
undviewTransition.finished
verwenden.
Informationen zur Aktivierung der Navigation
Sowohl bei pageswap
- als auch bei pagereveal
-Ereignissen können Sie auch Maßnahmen basierend auf den URLs der alten und der neuen Seite ergreifen.
Im MPA Stack Navigator hängt beispielsweise die Art der zu verwendenden Animation vom Navigationspfad ab:
- Wenn Sie von der Übersichtsseite zu einer Detailseite navigieren, müssen die neuen Inhalte von rechts nach links eingeblendet werden.
- Wenn Sie von der Detailseite zur Übersichtsseite wechseln, müssen die alten Inhalte von links nach rechts herausgeschoben werden.
Dazu benötigen Sie Informationen zur Navigation, die im Fall von pageswap
stattfinden wird oder im Fall von pagereveal
gerade erfolgt ist.
Dafür können Browser jetzt NavigationActivation
-Objekte mit Informationen zur Navigation am selben Ursprung anzeigen. Dieses Objekt stellt den verwendeten Navigationstyp, die aktuellen und die endgültigen Einträge im Zielverlauf aus navigation.entries()
der Navigation API bereit.
Auf einer aktivierten Seite können Sie über navigation.activation
auf dieses Objekt zugreifen. Bei pageswap
-Ereignissen kannst du über e.activation
darauf zugreifen.
Sehen Sie sich diese Profile-Demo an, in der NavigationActivation
-Informationen in den Ereignissen pageswap
und pagereveal
verwendet werden, um die view-transition-name
-Werte für die Elemente festzulegen, die an der Umstellung der Ansicht berücksichtigt werden müssen.
So müssen Sie nicht jedes einzelne Element in der Liste mit einem view-transition-name
im Vorfeld dekorieren. Stattdessen erfolgt dies direkt in JavaScript und nur bei Elementen, die es benötigen.
Der Code lautet wie folgt:
// OLD PAGE LOGIC
window.addEventListener('pageswap', async (e) => {
if (e.viewTransition) {
const targetUrl = new URL(e.activation.entry.url);
// Navigating to a profile page
if (isProfilePage(targetUrl)) {
const profile = extractProfileNameFromUrl(targetUrl);
// Set view-transition-name values on the clicked row
document.querySelector(`#${profile} span`).style.viewTransitionName = 'name';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'avatar';
// Remove view-transition-names after snapshots have been taken
// (this to deal with BFCache)
await e.viewTransition.finished;
document.querySelector(`#${profile} span`).style.viewTransitionName = 'none';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'none';
}
}
});
// NEW PAGE LOGIC
window.addEventListener('pagereveal', async (e) => {
if (e.viewTransition) {
const fromURL = new URL(navigation.activation.from.url);
const currentURL = new URL(navigation.activation.entry.url);
// Navigating from a profile page back to the homepage
if (isProfilePage(fromURL) && isHomePage(currentURL)) {
const profile = extractProfileNameFromUrl(currentURL);
// Set view-transition-name values on the elements in the list
document.querySelector(`#${profile} span`).style.viewTransitionName = 'name';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'avatar';
// Remove names after snapshots have been taken
// so that we're ready for the next navigation
await e.viewTransition.ready;
document.querySelector(`#${profile} span`).style.viewTransitionName = 'none';
document.querySelector(`#${profile} img`).style.viewTransitionName = 'none';
}
}
});
Der Code wird auch automatisch bereinigt, indem die view-transition-name
-Werte nach der Ausführung des Ansichtsübergangs entfernt werden. Auf diese Weise ist die Seite für aufeinanderfolgende Navigationen bereit und kann auch den Verlauf des Verlaufs durchlaufen.
Verwenden Sie zu diesem Zweck diese Dienstprogrammfunktion, die vorübergehend view-transition-name
-Werte festlegt.
const setTemporaryViewTransitionNames = async (entries, vtPromise) => {
for (const [$el, name] of entries) {
$el.style.viewTransitionName = name;
}
await vtPromise;
for (const [$el, name] of entries) {
$el.style.viewTransitionName = '';
}
}
Der vorherige Code kann jetzt so vereinfacht werden:
// OLD PAGE LOGIC
window.addEventListener('pageswap', async (e) => {
if (e.viewTransition) {
const targetUrl = new URL(e.activation.entry.url);
// Navigating to a profile page
if (isProfilePage(targetUrl)) {
const profile = extractProfileNameFromUrl(targetUrl);
// Set view-transition-name values on the clicked row
// Clean up after the page got replaced
setTemporaryViewTransitionNames([
[document.querySelector(`#${profile} span`), 'name'],
[document.querySelector(`#${profile} img`), 'avatar'],
], e.viewTransition.finished);
}
}
});
// NEW PAGE LOGIC
window.addEventListener('pagereveal', async (e) => {
if (e.viewTransition) {
const fromURL = new URL(navigation.activation.from.url);
const currentURL = new URL(navigation.activation.entry.url);
// Navigating from a profile page back to the homepage
if (isProfilePage(fromURL) && isHomePage(currentURL)) {
const profile = extractProfileNameFromUrl(currentURL);
// Set view-transition-name values on the elements in the list
// Clean up after the snapshots have been taken
setTemporaryViewTransitionNames([
[document.querySelector(`#${profile} span`), 'name'],
[document.querySelector(`#${profile} img`), 'avatar'],
], e.viewTransition.ready);
}
}
});
Warten, bis Inhalte mit Blockierungen für das Rendering geladen wurden
In einigen Fällen kann es sinnvoll sein, das erste Rendering einer Seite zurückzuhalten, bis ein bestimmtes Element im neuen DOM vorhanden ist. Dadurch wird ein Blinken vermieden und der Status, zu dem Sie animieren, stabilisiert.
Definieren Sie in <head>
mithilfe des folgenden Meta-Tags eine oder mehrere Element-IDs, die vorhanden sein müssen, bevor die Seite zum ersten Mal gerendert wird.
<link rel="expect" blocking="render" href="#section1">
Dieses Meta-Tag bedeutet, dass das Element im DOM vorhanden sein muss und nicht, dass der Inhalt geladen werden soll. Bei Bildern beispielsweise reicht es schon aus, dass das <img>
-Tag mit dem angegebenen id
im DOM-Baum vorhanden ist, damit die Bedingung als „true“ ausgewertet wird. Das Bild selbst wird möglicherweise noch geladen.
Bevor Sie sich vollständig auf das Blockieren des Renderings konzentrieren, sollten Sie sich darüber im Klaren sein, dass inkrementelles Rendering ein grundlegender Aspekt des Webs ist. Seien Sie also vorsichtig, wenn Sie das Rendering blockieren. Die Auswirkungen einer Blockierung des Renderings müssen von Fall zu Fall bewertet werden. Standardmäßig sollten Sie blocking=render
nur dann verwenden, wenn Sie die Auswirkungen auf Ihre Nutzer aktiv messen und messen können, indem Sie die Auswirkungen auf Ihre Core Web Vitals messen.
Übergangstypen bei dokumentenübergreifenden Ansichtsübergängen ansehen
Bei dokumentenübergreifenden Ansichtsübergängen werden auch Arten von Ansichtsübergängen unterstützt, um Animationen und Elemente anzupassen, die erfasst werden.
Wenn Sie beispielsweise bei einer Paginierung zur nächsten oder zur vorherigen Seite wechseln, können Sie unterschiedliche Animationen verwenden, je nachdem, ob Sie eine höhere oder eine niedrigere Seite aus der Abfolge aufrufen.
Wenn Sie diese Typen im Voraus festlegen möchten, fügen Sie sie in der @view-transition
-at-Regel hinzu:
@view-transition {
navigation: auto;
types: slide, forwards;
}
Um die Typen schnell festzulegen, verwenden Sie die Ereignisse pageswap
und pagereveal
, um den Wert von e.viewTransition.types
zu bearbeiten.
window.addEventListener("pagereveal", async (e) => {
if (e.viewTransition) {
const transitionType = determineTransitionType(navigation.activation.from, navigation.activation.entry);
e.viewTransition.types.add(transitionType);
}
});
Die Typen werden nicht automatisch vom ViewTransition
-Objekt auf der alten Seite zum ViewTransition
-Objekt der neuen Seite übernommen. Sie müssen mindestens den Typ bzw. die Typen festlegen, die auf der neuen Seite verwendet werden sollen, damit die Animationen wie erwartet angezeigt werden.
Verwenden Sie die Pseudoklassenauswahl :active-view-transition-type()
wie bei Übergängen der Ansicht desselben Dokuments, um auf diese Typen zu reagieren.
/* 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 */
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;
}
}
Da Typen nur für einen Active View-Übergang gelten, werden Typen automatisch bereinigt, wenn ein Übergang von der Ansicht abgeschlossen ist. Aus diesem Grund funktionieren Typen gut mit Funktionen wie BFCache.
Demo
In der folgenden Demo zur Paginierung blättern die Seiteninhalte je nach Seitennummer vor oder zurück.
Der zu verwendende Übergangstyp wird in den pagereveal
- und pageswap
-Ereignissen ermittelt, indem die zu und von den URLs betrachtet werden.
const determineTransitionType = (fromNavigationEntry, toNavigationEntry) => {
const currentURL = new URL(fromNavigationEntry.url);
const destinationURL = new URL(toNavigationEntry.url);
const currentPathname = currentURL.pathname;
const destinationPathname = destinationURL.pathname;
if (currentPathname === destinationPathname) {
return "reload";
} else {
const currentPageIndex = extractPageIndexFromPath(currentPathname);
const destinationPageIndex = extractPageIndexFromPath(destinationPathname);
if (currentPageIndex > destinationPageIndex) {
return 'backwards';
}
if (currentPageIndex < destinationPageIndex) {
return 'forwards';
}
return 'unknown';
}
};
Feedback
Wir freuen uns immer über Feedback von Entwicklern. Melden Sie ein Problem bei der Preisvergleichsportal-Arbeitsgruppe auf GitHub, um Vorschläge und Fragen zu teilen. Stellen Sie dem Problem „[css-view-transitions]
“ als Präfix vor.
Falls ein Fehler auftritt, melde den Fehler in Chromium.