Wanneer er een weergaveovergang plaatsvindt tussen twee verschillende documenten, wordt dit een weergaveovergang tussen verschillende documenten genoemd. Dit is doorgaans het geval bij toepassingen met meerdere pagina's (MPA). Overgangen tussen documentweergaven worden ondersteund in Chrome vanaf Chrome 126.
Browserondersteuning
Overgangen tussen weergaven tussen documenten zijn gebaseerd op precies dezelfde bouwstenen en principes als overgangen tussen weergaven binnen dezelfde documenten , wat zeer opzettelijk is:
- De browser maakt momentopnamen van elementen die een unieke
view-transition-name
hebben op zowel de oude als de nieuwe pagina. - De DOM wordt bijgewerkt terwijl weergave wordt onderdrukt.
- En ten slotte worden de overgangen mogelijk gemaakt door CSS-animaties.
Wat anders is in vergelijking met weergaveovergangen van hetzelfde document, is dat u bij weergaveovergangen tussen verschillende documenten document.startViewTransition
niet hoeft aan te roepen om een weergaveovergang te starten. In plaats daarvan is de trigger voor een overgang tussen documentweergaven een navigatie met dezelfde oorsprong van de ene pagina naar de andere, een actie die doorgaans wordt uitgevoerd doordat de gebruiker van uw website op een koppeling klikt.
Met andere woorden: er is geen API die kan worden aangeroepen om een weergaveovergang tussen twee documenten te starten. Er zijn echter twee voorwaarden waaraan moet worden voldaan:
- Beide documenten moeten op dezelfde oorsprong bestaan.
- Beide pagina's moeten zich aanmelden om de weergaveovergang mogelijk te maken.
Beide voorwaarden worden verderop in dit document uitgelegd.
Overgangen tussen weergaven tussen documenten zijn beperkt tot navigatie met dezelfde oorsprong
Overgangen tussen weergaven tussen documenten zijn beperkt tot navigatie met dezelfde oorsprong . Een navigatie wordt als dezelfde oorsprong beschouwd als de oorsprong van beide deelnemende pagina's dezelfde is.
De oorsprong van een pagina is een combinatie van het gebruikte schema, de hostnaam en de poort, zoals beschreven op web.dev .
U kunt bijvoorbeeld een overgang tussen documentweergaven maken wanneer u navigeert van developer.chrome.com
naar developer.chrome.com/blog
, aangezien deze van dezelfde oorsprong zijn. U kunt die overgang niet hebben als u van developer.chrome.com
naar www.chrome.com
navigeert, omdat deze cross-origin en dezelfde site zijn.
Overgangen tussen documentweergaven zijn opt-in
Om een overgang tussen twee documenten tussen documenten te kunnen weergeven, moeten beide deelnemende pagina's zich hiervoor aanmelden. Dit gebeurt met de @view-transition
at-regel in CSS.
Stel in de @view-transition
at-regel de navigation
in op auto
om weergaveovergangen in te schakelen voor navigatie tussen verschillende documenten en met dezelfde oorsprong.
@view-transition {
navigation: auto;
}
Door navigation
in te stellen op auto
geeft u toestemming voor het toestaan van weergaveovergangen voor de volgende navigatietypes :
-
traverse
-
push
ofreplace
, als de activering niet door de gebruiker is geïnitieerd via de UI-mechanismen van de browser.
Navigaties die zijn uitgesloten van auto
zijn bijvoorbeeld navigeren via de URL-adresbalk of klikken op een bladwijzer, evenals elke vorm van door de gebruiker of een script geïnitieerd herladen.
Als een navigatie te lang duurt (meer dan vier seconden in het geval van Chrome), wordt de weergaveovergang overgeslagen met een TimeoutError
DOMException
.
Demo voor overgangen tussen documenten
Bekijk de volgende demo waarin weergaveovergangen worden gebruikt om een Stack Navigator-demo te maken. Er zijn hier geen oproepen naar document.startViewTransition()
De weergaveovergangen worden geactiveerd door van de ene pagina naar de andere te navigeren.
Pas overgangen tussen documenten aan
Om de overgangen tussen documenten aan te passen, zijn er enkele webplatformfuncties die u kunt gebruiken.
Deze functies maken geen deel uit van de View Transition API-specificatie zelf, maar zijn ontworpen om in combinatie daarmee te worden gebruikt.
De pageswap
en pagereveal
Om u in staat te stellen weergaveovergangen tussen documenten aan te passen, bevat de HTML-specificatie twee nieuwe gebeurtenissen die u kunt gebruiken: pageswap
en pagereveal
.
Deze twee gebeurtenissen worden geactiveerd voor elke navigatie tussen verschillende documenten met dezelfde oorsprong, ongeacht of er een weergaveovergang op het punt staat te gebeuren of niet. Als er tussen de twee pagina's een weergaveovergang gaat plaatsvinden, kunt u voor deze gebeurtenissen toegang krijgen tot het ViewTransition
object met behulp van de eigenschap viewTransition
.
- De
pageswap
gebeurtenis wordt geactiveerd voordat het laatste frame van een pagina wordt weergegeven. U kunt dit gebruiken om op het laatste moment nog enkele wijzigingen aan te brengen op de uitgaande pagina, vlak voordat de oude snapshots worden gemaakt. - De
pagereveal
-gebeurtenis wordt op een pagina geactiveerd nadat deze is geïnitialiseerd of opnieuw geactiveerd, maar vóór de eerste weergavemogelijkheid. Hiermee kunt u de nieuwe pagina aanpassen voordat de nieuwe snapshots worden gemaakt.
U kunt deze gebeurtenissen bijvoorbeeld gebruiken om snel bepaalde waarden view-transition-name
in te stellen of te wijzigen, of om gegevens van het ene document naar het andere door te geven door gegevens uit sessionStorage
te schrijven en te lezen om de weergave-overgang aan te passen voordat deze daadwerkelijk wordt uitgevoerd.
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');
}
});
Als je wilt, kun je ervoor kiezen om de overgang in beide evenementen over te slaan.
window.addEventListener("pagereveal", async (e) => {
if (e.viewTransition) {
if (goodReasonToSkipTheViewTransition()) {
e.viewTransition.skipTransition();
}
}
}
Het ViewTransition
object in pageswap
en pagereveal
zijn twee verschillende objecten. Ze gaan ook anders om met de verschillende beloften :
-
pageswap
: Zodra het document verborgen is, wordt het oudeViewTransition
object overgeslagen. Wanneer dat gebeurt, weigertviewTransition.ready
en wordtviewTransition.finished
opgelost. -
pagereveal
: DeupdateCallBack
belofte is op dit punt al opgelost. U kunt gebruik maken van de beloftenviewTransition.ready
enviewTransition.finished
.
Informatie over navigatie-activatie
Bij zowel pageswap
als pagereveal
kunt u ook actie ondernemen op basis van de URL's van de oude en nieuwe pagina's.
In de MPA Stack Navigator hangt het type animatie dat u wilt gebruiken bijvoorbeeld af van het navigatiepad:
- Wanneer u van de overzichtspagina naar een detailpagina navigeert, moet de nieuwe inhoud van rechts naar links schuiven.
- Wanneer u van de detailpagina naar de overzichtspagina navigeert, moet de oude inhoud van links naar rechts naar buiten schuiven.
Hiervoor heeft u informatie nodig over de navigatie die, in het geval van pageswap
, gaat plaatsvinden of, in het geval van pagereveal
net heeft plaatsgevonden.
Hiervoor kunnen browsers nu NavigationActivation
objecten weergeven die informatie bevatten over navigatie met dezelfde oorsprong. Dit object geeft het gebruikte navigatietype, de huidige en de uiteindelijke bestemmingsgeschiedenisgegevens weer zoals gevonden in navigation.entries()
van de Navigatie-API .
Op een geactiveerde pagina heeft u toegang tot dit object via navigation.activation
. In het pageswap
kunt u hiertoe toegang krijgen via e.activation
.
Bekijk deze Profielen-demo die gebruikmaakt van NavigationActivation
in de gebeurtenissen pageswap
en pagereveal
om de view-transition-name
waarden in te stellen voor de elementen die moeten deelnemen aan de weergaveovergang.
Op die manier hoeft u niet elk item in de lijst vooraf te voorzien van een view-transition-name
. In plaats daarvan gebeurt dit just-in-time met behulp van JavaScript, alleen op elementen die dit nodig hebben.
De code is als volgt:
// 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';
}
}
});
De code ruimt zichzelf ook op door de view-transition-name
waarden te verwijderen nadat de view-overgang is uitgevoerd. Op deze manier is de pagina klaar voor opeenvolgende navigatie en kan deze ook de geschiedenis doorkruisen.
Om hierbij te helpen, gebruikt u deze hulpprogrammafunctie die tijdelijk view-transition-name
instelt.
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 = '';
}
}
De vorige code kan nu als volgt worden vereenvoudigd:
// 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);
}
}
});
Wacht tot de inhoud is geladen met weergaveblokkering
Browserondersteuning
In sommige gevallen wilt u misschien de eerste weergave van een pagina uitstellen totdat een bepaald element aanwezig is in de nieuwe DOM. Dit voorkomt knipperen en zorgt ervoor dat de status waarnaar u animeert stabiel is.
Definieer in de <head>
een of meer element-ID's die aanwezig moeten zijn voordat de pagina voor de eerste keer wordt weergegeven, met behulp van de volgende metatag.
<link rel="expect" blocking="render" href="#section1">
Deze metatag betekent dat het element aanwezig moet zijn in de DOM, niet dat de inhoud moet worden geladen. Bij afbeeldingen is bijvoorbeeld de aanwezigheid van de tag <img>
met de opgegeven id
in de DOM-structuur voldoende om de voorwaarde als waar te laten evalueren. De afbeelding zelf kan nog steeds worden geladen.
Voordat u all-in gaat op het blokkeren van weergave, moet u zich ervan bewust zijn dat incrementele weergave een fundamenteel aspect van het web is, dus wees voorzichtig als u ervoor kiest om weergave te blokkeren. De impact van het blokkeren van weergave moet van geval tot geval worden beoordeeld. Vermijd standaard het gebruik van blocking=render
tenzij u de impact die dit heeft op uw gebruikers actief kunt meten en peilen, door de impact op uw Core Web Vitals te meten.
Bekijk overgangstypen in overgangen tussen documenten
Weergaveovergangen tussen documenten ondersteunen ook typen weergaveovergangen om de animaties aan te passen en welke elementen worden vastgelegd.
Als u bijvoorbeeld naar de volgende of vorige pagina in een paginering gaat, wilt u mogelijk verschillende animaties gebruiken, afhankelijk van of u naar een hogere pagina of een lagere pagina in de reeks gaat.
Om deze typen vooraf in te stellen, voegt u de typen toe aan de @view-transition
at-regel:
@view-transition {
navigation: auto;
types: slide, forwards;
}
Om de typen direct in te stellen, gebruikt u de gebeurtenissen pageswap
en pagereveal
om de waarde van e.viewTransition.types
te manipuleren.
window.addEventListener("pagereveal", async (e) => {
if (e.viewTransition) {
const transitionType = determineTransitionType(navigation.activation.from, navigation.activation.entry);
e.viewTransition.types.add(transitionType);
}
});
De typen worden niet automatisch overgedragen van het ViewTransition
object op de oude pagina naar het ViewTransition
object van de nieuwe pagina. U moet bepalen welke type(n) u op zijn minst op de nieuwe pagina wilt gebruiken, zodat de animaties naar verwachting kunnen worden uitgevoerd.
Om op deze typen te reageren, gebruikt u de :active-view-transition-type()
pseudo-klasse selector op dezelfde manier als bij weergave-overgangen van hetzelfde document
/* 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;
}
}
Omdat typen alleen van toepassing zijn op een actieve weergaveovergang, worden typen automatisch opgeschoond wanneer een weergaveovergang is voltooid. Daarom werken typen goed met functies als BFCache .
Demo
In de volgende pagineringsdemo schuift de pagina-inhoud vooruit of achteruit op basis van het paginanummer waarnaar u navigeert.
Het te gebruiken transitietype wordt bepaald in de pagereveal
en pageswap
gebeurtenissen door te kijken naar de van en naar URL's.
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
Feedback van ontwikkelaars wordt altijd op prijs gesteld. Om te delen kunt u een probleem indienen bij de CSS Working Group op GitHub met suggesties en vragen. Geef uw probleem een voorvoegsel met [css-view-transitions]
. Mocht je een bug tegenkomen, dien dan een Chromium-bug in .