From c7dcd4eb22babe0ca1a0f55699474555cea01326 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 18 Mar 2024 13:00:12 +0000 Subject: [PATCH 01/53] Document cross-document view transitions --- .../api/document/startviewtransition/index.md | 2 +- .../web/api/view_transitions_api/index.md | 278 ++----------- .../api/view_transitions_api/using/index.md | 380 ++++++++++++++++++ files/en-us/web/api/viewtransition/index.md | 2 +- .../index.md | 2 +- .../index.md | 2 +- .../_doublecolon_view-transition-new/index.md | 2 +- .../_doublecolon_view-transition-old/index.md | 2 +- .../css/_doublecolon_view-transition/index.md | 2 +- files/jsondata/GroupData.json | 10 +- 10 files changed, 430 insertions(+), 252 deletions(-) create mode 100644 files/en-us/web/api/view_transitions_api/using/index.md diff --git a/files/en-us/web/api/document/startviewtransition/index.md b/files/en-us/web/api/document/startviewtransition/index.md index b49c42c6fa5b8b6..5a9abbf34400190 100644 --- a/files/en-us/web/api/document/startviewtransition/index.md +++ b/files/en-us/web/api/document/startviewtransition/index.md @@ -13,7 +13,7 @@ browser-compat: api.Document.startViewTransition The **`startViewTransition()`** method of the {{domxref("View Transitions API", "View Transitions API", "", "nocode")}} starts a new view transition and returns a {{domxref("ViewTransition")}} object to represent it. -When `startViewTransition()` is invoked, a sequence of steps is followed as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process). +When `startViewTransition()` is invoked, a sequence of steps is followed as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_process). ## Syntax diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index a54185eac026287..91a234e13da04fa 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -9,259 +9,36 @@ browser-compat: api.Document.startViewTransition {{SeeCompatTable}}{{DefaultAPISidebar("View Transitions API")}} -The **View Transitions API** provides a mechanism for easily creating animated transitions between different DOM states while also updating the DOM contents in a single step. +The **View Transitions API** provides a mechanism for easily creating animated transitions between different website views. This includes animating between DOM states in a single-page app (SPA), and animating the navigation between documents in a multi-page app (MPA). ## Concepts and usage View transitions are a popular design choice for reducing users' cognitive load, helping them stay in context, and reducing perceived loading latency as they move between states or views of an application. -However, creating view transitions on the web has historically been difficult. Transitions between states in single-page apps (SPAs) tend to involve writing significant CSS and JavaScript to: +However, creating view transitions on the web has historically been difficult: -- Handle the loading and positioning of the old and new content. -- Animate the old and new states to create the transition. -- Stop accidental user interactions with the old content from causing problems. -- Remove the old content once the transition is complete. +- Transitions between states in single-page apps (SPAs) tend to involve writing significant CSS and JavaScript to: + - Handle the loading and positioning of the old and new content. + - Animate the old and new states to create the transition. + - Stop accidental user interactions with the old content from causing problems. + - Remove the old content once the transition is complete. + Accessibility issues like loss of reading position, focus confusion, and strange live region announcement behavior can also result from having the new and old content both present in the DOM at once. +- Cross-document view transitions (i.e. across navigations between different pages in MPAs) have historically been impossible. -Accessibility issues like loss of reading position, focus confusion, and strange live region announcement behavior can also result from having the new and old content both present in the DOM at once. In addition, cross-document view transitions (i.e. across different pages in regular, non-SPA websites) are impossible. +The View Transitions API provides an easy way of handling the required view changes and transition animations for both the above use cases. -The View Transitions API provides a much easier way of handling the required DOM changes and transition animations. +Creating a view transition that uses the browser's default transition animations is very quick to do, and there are features that allow you to both customize the transition animation and manipulate the view transition itself (for example specify circumstances under which the animation is skipped), for both SPA and MPA view transitions. -> **Note:** The View Transitions API doesn't currently enable cross-document view transitions, but this is planned for a future level of the spec and is actively being worked on. - -### Creating a basic view transition - -As an example, an SPA may include functionality to fetch new content and update the DOM in response to an event of some kind, such as a navigation link being clicked or an update being pushed from the server. In our [Basic View Transitions demo](https://mdn.github.io/dom-examples/view-transitions/) we've simplified this to a `displayNewImage()` function that shows a new full-size image based on the thumbnail that was clicked. We've encapsulated this inside an `updateView()` function that only calls the View Transition API if the browser supports it: - -```js -function updateView(event) { - // Handle the difference in whether the event is fired on the or the - const targetIdentifier = event.target.firstChild || event.target; - - const displayNewImage = () => { - const mainSrc = `${targetIdentifier.src.split("_th.jpg")[0]}.jpg`; - galleryImg.src = mainSrc; - galleryCaption.textContent = targetIdentifier.alt; - }; - - // Fallback for browsers that don't support View Transitions: - if (!document.startViewTransition) { - displayNewImage(); - return; - } - - // With View Transitions: - const transition = document.startViewTransition(() => displayNewImage()); -} -``` - -This code is enough to handle the transition between displayed images. Supporting browsers will show the change from old to new images and captions as a smooth cross-fade (the default view transition). It will still work in non-supporting browsers but without the nice animation. - -It is also worth mentioning that `startViewTransition()` returns a {{domxref("ViewTransition")}} instance, which includes several promises, allowing you to run code in response to different parts of the view transition process being reached. - -### The view transition process - -Let's walk through how this works: - -1. When {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} is called, the API takes a screenshot of the current page. -2. Next, the callback passed to `startViewTransition()` is invoked, in this case `displayNewImage`, which causes the DOM to change. - - When the callback has run successfully, the {{domxref("ViewTransition.updateCallbackDone")}} promise fulfills, allowing you to respond to the DOM updating. - -3. The API captures the new state of the page as a live representation. -4. The API constructs a pseudo-element tree with the following structure: - - ```plain - ::view-transition - └─ ::view-transition-group(root) - └─ ::view-transition-image-pair(root) - ├─ ::view-transition-old(root) - └─ ::view-transition-new(root) - ``` - - - {{cssxref("::view-transition")}} is the root of view transitions overlay, which contains all view transitions and sits over the top of all other page content. - - {{cssxref("::view-transition-old")}} is the screenshot of the old page view, and {{cssxref("::view-transition-new")}} is the live representation of the new page view. Both of these render as replaced content, in the same manner as an {{htmlelement("img")}} or {{htmlelement("video")}}, meaning that they can be styled with handy properties like {{cssxref("object-fit")}} and {{cssxref("object-position")}}. - - When the transition animation is about to run, the {{domxref("ViewTransition.ready")}} promise fulfills, allowing you to respond by running a custom JavaScript animation instead of the default, for example. - -5. The old page view animates from {{cssxref("opacity")}} 1 to 0, while the new view animates from `opacity` 0 to 1, which is what creates the default cross-fade. -6. When the transition animation has reached its end state, the {{domxref("ViewTransition.finished")}} promise fulfills, allowing you to respond. - -### Different transitions for different elements - -At the moment, all of the different elements that change when the DOM updates are transitioned using the same animation. If you want different elements to animate differently from the default "root" animation, you can separate them out using the {{cssxref("view-transition-name")}} property. For example: - -```css -figcaption { - view-transition-name: figure-caption; -} -``` - -We've given the {{htmlelement("figcaption")}} element a `view-transition-name` of `figure-caption` to separate it from the rest of the page in terms of view transitions. - -With this CSS applied, the pseudo-element tree will now look like this: - -```plain -::view-transition -├─ ::view-transition-group(root) -│ └─ ::view-transition-image-pair(root) -│ ├─ ::view-transition-old(root) -│ └─ ::view-transition-new(root) -└─ ::view-transition-group(figure-caption) - └─ ::view-transition-image-pair(figure-caption) - ├─ ::view-transition-old(figure-caption) - └─ ::view-transition-new(figure-caption) -``` - -The existence of the second set of pseudo-elements allows separate view transition styling to be applied just to the `
`. The different old and new page view captures are handled completely separate from one another. - -The value of `view-transition-name` can be anything you want except for `none` — the `none` value specifically means that the element will not participate in a view transition. - -> **Note:** `view-transition-name` must be unique. If two rendered elements have the same `view-transition-name` at the same time, {{domxref("ViewTransition.ready")}} will reject and the transition will be skipped. - -### Customizing your animations - -The View Transitions pseudo-elements have default [CSS Animations](/en-US/docs/Web/CSS/CSS_animations) applied (which are detailed in their [reference pages](#css_additions)). - -Notably, transitions for `height`, `width`, `position`, and `transform` do not use the smooth cross-fade animation. Instead, height and width transitions apply a smooth scaling animation. Meanwhile, position and transform transitions apply smooth movement animations to the element. - -You can modify the default animation in any way you want using regular CSS. - -For example, to change the speed of it: - -```css -::view-transition-old(root), -::view-transition-new(root) { - animation-duration: 0.5s; -} -``` - -Let's look at something more interesting — a custom animation for the `
`: - -```css -@keyframes grow-x { - from { - transform: scaleX(0); - } - to { - transform: scaleX(1); - } -} - -@keyframes shrink-x { - from { - transform: scaleX(1); - } - to { - transform: scaleX(0); - } -} - -::view-transition-old(figure-caption), -::view-transition-new(figure-caption) { - height: auto; - right: 0; - left: auto; - transform-origin: right center; -} - -::view-transition-old(figure-caption) { - animation: 0.25s linear both shrink-x; -} - -::view-transition-new(figure-caption) { - animation: 0.25s 0.25s linear both grow-x; -} -``` - -Here we've created a custom CSS animation and applied it to the `::view-transition-old(figure-caption)` and `::view-transition-new(figure-caption)` pseudo-elements. We've also added a number of other styles to both to keep them in the same place and stop the default styling from interfering with our custom animations. - -Note that we also discovered another transition option that is simpler and produced a nicer result than the above. Our final `
` view transition ended up looking like this: - -```css -figcaption { - view-transition-name: figure-caption; -} - -::view-transition-old(figure-caption), -::view-transition-new(figure-caption) { - height: 100%; -} -``` - -This works because, by default, `::view-transition-group` transitions width and height between the old and new views. We just needed to set a fixed `height` on both states to make it work. - -> **Note:** [Smooth and simple transitions with the View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/) contains several other customization examples. - -### Controlling animations with JavaScript - -The {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method returns a {{domxref("ViewTransition")}} object instance, which contains several promise members allowing you to run JavaScript in response to different states of the transition being reached. For example, {{domxref("ViewTransition.ready")}} fulfills once the pseudo-element tree is created and the animation is about to start, whereas {{domxref("ViewTransition.finished")}} fulfills once the animation is finished, and the new page view is visible and interactive to the user. - -For example, the following JavaScript could be used to create a circular reveal view transition emanating from the position of the user's cursor on click, with animation provided by the {{domxref("Web Animations API", "Web Animations API", "", "nocode")}}. - -```js -// Store the last click event -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), - ); - - // Create 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)", - }, - ); - }); -} -``` - -This animation also requires the following CSS, to turn off the default CSS animation and stop the old and new view states from blending in any way (the new state "wipes" right over the top of the old state, rather than transitioning in): - -```css -::view-transition-image-pair(root) { - isolation: auto; -} - -::view-transition-old(root), -::view-transition-new(root) { - animation: none; - mix-blend-mode: normal; - display: block; -} -``` +See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Using) for more information. ## Interfaces +- {{domxref("NavigationActivation")}} + - : Represents a cross-document navigation; contains the navigation type and current and destination document history entries. +- {{domxref("PageRevealEvent")}} + - : The event object for the {{domxref("Window.pagereveal_event", "pagereveal")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. +- {{domxref("PageSwapEvent")}} + - : The event object for the {{domxref("Window.pageswap_event", "pageswap")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination documents. - {{domxref("ViewTransition")}} - : Represents a view transition, and provides functionality to react to the transition reaching different states (e.g. ready to run the animation, or animation finished) or skip the transition altogether. @@ -269,9 +46,23 @@ This animation also requires the following CSS, to turn off the default CSS anim - {{domxref("Document.startViewTransition()")}} - : Starts a new view transition and returns a {{domxref("ViewTransition")}} object to represent it. + The {{domxref("Window")}} {{domxref("Window.pagereveal_event", "pagereveal")}} event + - : Fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](https://web.dev/articles/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). + The {{domxref("Window")}} {{domxref("Window.pageswap_event", "pageswap")}} event + - : Fired when a document is about to be unloaded due to a navigation. + +## HTML additions + +- [``](/en-US/docs/Web/HTML/Attributes/rel#expect) + - : Identifies the most critical content in the associated document for the user's initial view of the page. Document rendering will be blocked until the critical content has been parsed, ensuring a consistent first paint (and therefore, view transition) across all supporting browsers. ## CSS additions +### At-rules + +- {{cssxref("@view-transition")}} + - : Used to opt in the current and destination documents to undergoing a view transition, in the case of a cross-document navigation. + ### Properties - {{cssxref("view-transition-name")}} @@ -292,8 +83,9 @@ This animation also requires the following CSS, to turn off the default CSS anim ## Examples -- [Basic View Transitions demo](https://mdn.github.io/dom-examples/view-transitions/): A basic image gallery demo with separate transitions between old and new images, and old and new captions. -- [HTTP 203 playlist](https://http203-playlist.netlify.app/): A more sophisticated video player demo app that features a number of different view transitions, many of which are explained in [Smooth and simple transitions with the View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/). +- [Basic View Transitions SPA demo](https://mdn.github.io/dom-examples/view-transitions/spa/): A basic image gallery demo with separate transitions between old and new images, and old and new captions. +- [Basic View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transitions/mpa/): A sample two-page site that demonstrates usage of cross-document (MPA) view transitions, providing a smooth transition when the two pages are navigated between. +- [HTTP 203 playlist](https://http203-playlist.netlify.app/): A video player demo app that features a number of different SPA view transitions, many of which are explained in [Smooth and simple transitions with the View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/). ## Specifications diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md new file mode 100644 index 000000000000000..ddc76d5f2f73f3a --- /dev/null +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -0,0 +1,380 @@ +--- +title: Using the View Transitions API +slug: Web/API/View_Transitions_API/Using +page-type: guide +status: + - experimental +--- + +{{DefaultAPISidebar("View Transitions API")}} + +This article explains the theory behind how the [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) works, how to create view transitions and customize the transition animations, and how to manipulate active view transitions. This covers view transitions for both DOM state updates in a single-page app (SPA), and navigating between documents in a multi-page app (MPA). + +## The view transition process + +Let's walk through the process by which a view transition works: + +1. A view transition is triggered. How this is done depends on the type of view transition: + - In the case of same-document transitions (SPAs), a view transition is triggered by passing the function that would trigger the view change DOM update as a callback to the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method. + - In the case of cross-document transitions (MPAs), a view transition is triggered by initiating navigation to a new document. Both the current and destination documents of the navigation need to opt-in to the view transition by including a {{cssxref("@view-transition")}} at rule in their CSS with a `navigation` descriptor of `auto`. + > **Note:** An active view transition has an associated {{domxref("ViewTransition")}} instance (for example, returned by `startViewTransition()` in the case of same-document (SPA) transitions). The `ViewTransition` object includes several promises, allowing you to run code in response to different parts of the view transition process being reached. See [Controlling view transitions with JavaScript](#controlling_view_transitions_with_javascript) for mroe information. +2. The API takes a screenshot of the current (old page) view. +3. The view change occurs: + - In the case of same-document transitions (SPAs), the callback passed to `startViewTransition()` is invoked, which causes the DOM to change. + > **Note:** When the callback has run successfully, the {{domxref("ViewTransition.updateCallbackDone")}} promise fulfills, allowing you to respond to the DOM updating. + - In the case of cross-document transitions (MPAs), the navigation occurs between the current and destination documents. +4. The API captures the new view as a live representation. + > **Note:** At this point, the view transition is about to run, and the {{domxref("ViewTransition.ready")}} promise fulfills, allowing you to respond by running a custom JavaScript animation instead of the default, for example. +5. The old page view animates "out", while the new view animates "in". By default, the old view animates from {{cssxref("opacity")}} 1 to 0 and the new view animates from `opacity` 0 to 1, which creates a cross-fade. +6. When the transition animation has reached its end state, the {{domxref("ViewTransition.finished")}} promise fulfills, allowing you to respond. + +### The view transition pseudo-element tree + +To handle creating the outbound and inbound transition animations, the API constructs a pseudo-element tree with the following structure: + +```plain +::view-transition +└─ ::view-transition-group(root) + └─ ::view-transition-image-pair(root) + ├─ ::view-transition-old(root) + └─ ::view-transition-new(root) +``` + +The most interesting parts of this structure are as follows: + +- {{cssxref("::view-transition")}} is the root of view transitions overlay, which contains all view transitions and sits over the top of all other page content. +- {{cssxref("::view-transition-old")}} targets the screenshot of the old page view, and {{cssxref("::view-transition-new")}} targets the live representation of the new page view. Both of these render as replaced content, in the same manner as an {{htmlelement("img")}} or {{htmlelement("video")}}, meaning that they can be styled with handy properties like {{cssxref("object-fit")}} and {{cssxref("object-position")}}. +- The `root` argument specifies the default grouping for the view transition — that the view transition animation will apply to all DOM elements that change when the view is updated. It is possible to use target different DOM elements with different custom view transition animations — see [Different transitions for different elements](#different_transitions_for_different_elements). + +> **Note:** As you'll see later, to customize the outbound and inbound animations you need to target the {{cssxref("::view-transition-old")}} and {{cssxref("::view-transition-new")}} pseudo-elements with your animations, respectively. + +- In the case of same-document transitions (SPAs), the pseudo-element tree is made available in the document. +- In the case of cross-document transitions (MPAs), the pseudo-element tree is made available in both the current and destination documents. + +## Creating a basic view transition + +This section illustates how to create a basic view transition, in both the SPA and MPA case. + +### Basic SPA view transition + +As an example, an SPA may include functionality to fetch new content and update the DOM in response to an event of some kind, such as a navigation link being clicked or an update being pushed from the server. In our [View Transitions SPA demo](https://mdn.github.io/dom-examples/view-transitions/spa/) we've simplified this to a `displayNewImage()` function that shows a new full-size image based on the thumbnail that was clicked. We've encapsulated this inside an `updateView()` function that only calls the View Transition API if the browser supports it: + +```js +function updateView(event) { + // Handle the difference in whether the event is fired on the or the + const targetIdentifier = event.target.firstChild || event.target; + + const displayNewImage = () => { + const mainSrc = `${targetIdentifier.src.split("_th.jpg")[0]}.jpg`; + galleryImg.src = mainSrc; + galleryCaption.textContent = targetIdentifier.alt; + }; + + // Fallback for browsers that don't support View Transitions: + if (!document.startViewTransition) { + displayNewImage(); + return; + } + + // With View Transitions: + const transition = document.startViewTransition(() => displayNewImage()); +} +``` + +This code is enough to handle the transition between displayed images. Supporting browsers will show the change from old to new images and captions as a smooth cross-fade (the default view transition). It will still work in non-supporting browsers but without the nice animation. + +### Basic MPA view transition + +When creating a cross-document (MPA) view transition, the process is even simpler than for SPAs — no JavaScript is required, as the view update is triggered by a document navigation rather than a JavaScript-initiated DOM change. To enable a basic MPA view transition, you need to specify a {{cssxref("@view-transition")}} at rule in the CSS for both the current and destination documents to opt them in, like so: + +```css +@view-transition { + navigation: auto; +} +``` + +Our [View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transitions/mpa/) shows this at-rule in action, and additionally demonstrates how to [customize the outbound and inbound animations](#customizing_your_animations) of the view transition. + +> **Note:** Currently MPA view transitions can only be created between same-origin documents, but this restriction may be relaxed in future implementations. + +## Customizing your animations + +The View Transitions pseudo-elements have default [CSS Animations](/en-US/docs/Web/CSS/CSS_animations) applied (which are detailed in their [reference pages](/en-US/docs/Web/API/View_Transitions_API#pseudo-elements)). + +Most appearence transitions are given a default smooth cross-fade animation, as mentioned above. There are some exceptions: + +- `height` and `width` transitions have a smooth scaling animation applied. +- `position` and `transform` transitions have a smooth movement animation applied. + +You can modify the default animations in any way you want using regular CSS — target the "from" animation with {{cssxref("::view-transition-old")}}, and the "to" animation with {{cssxref("::view-transition-new")}}. + +For example, to change the speed of both: + +```css +::view-transition-old(root), +::view-transition-new(root) { + animation-duration: 0.5s; +} +``` + +In the case of cross-document (MPA) transitions, the CSS needs to be included in the current _and_ destination documents. You might think that you can just target `::view-transition-old(root)` in the current document and `::view-transition-new(root)` in the destination document but this results in some strange behavior, plus you'll probably want to navigate in the other direction at some point, in which case the old current document will become the new destination document, and the old destination document will become the new current document. + +Our [View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transitions/mpa/) includes the above CSS, but takes the customization a step further, defining custom animations and applying them to the `::view-transition-old(root)` and `::view-transition-new(root)` pseudo-elements. The result is that the default cross-fade transition is swapped out for a "swipe up" transition when navigation occurs: + +```css +/* Create a custom animation */ + +@keyframes move-out { + from { + transform: translateY(0%); + } + + to { + transform: translateY(-100%); + } +} + +@keyframes move-in { + from { + transform: translateY(100%); + } + + to { + transform: translateY(0%); + } +} + +/* Apply the custom animation to the old and new page states */ + +::view-transition-old(root) { + animation: 0.4s ease-in both move-out; +} + +::view-transition-new(root) { + animation: 0.4s ease-in both move-in; +} +``` + +## Different transitions for different elements + +By default, all of the different elements that change during the view update are transitioned using the same animation. If you want some elements to animate differently from the default `root` animation, you can separate them out using the {{cssxref("view-transition-name")}} property. For example, in our [View Transitions SPA demo](https://mdn.github.io/dom-examples/view-transitions/spa/) the {{htmlelement("figcaption")}} elements are given a `view-transition-name` of `figure-caption` to separate them from the rest of the page in terms of view transitions: + +```css +figcaption { + view-transition-name: figure-caption; +} +``` + +With this CSS applied, the generated pseudo-element tree will now look like this: + +```plain +::view-transition +├─ ::view-transition-group(root) +│ └─ ::view-transition-image-pair(root) +│ ├─ ::view-transition-old(root) +│ └─ ::view-transition-new(root) +└─ ::view-transition-group(figure-caption) + └─ ::view-transition-image-pair(figure-caption) + ├─ ::view-transition-old(figure-caption) + └─ ::view-transition-new(figure-caption) +``` + +The existence of the second set of pseudo-elements allows separate view transition styling to be applied just to the `
`. The different old and new view captures are handled separately from one another. + +> **Note:** The value of `view-transition-name` can be anything you want except for `none` — the `none` value specifically means that the element will not participate in a view transition. +> +> `view-transition-name` values must also be unique. If two rendered elements have the same `view-transition-name` at the same time, {{domxref("ViewTransition.ready")}} will reject and the transition will be skipped. + +The following code applies a custom animation just to the `
`: + +```css +@keyframes grow-x { + from { + transform: scaleX(0); + } + to { + transform: scaleX(1); + } +} + +@keyframes shrink-x { + from { + transform: scaleX(1); + } + to { + transform: scaleX(0); + } +} + +::view-transition-old(figure-caption), +::view-transition-new(figure-caption) { + height: auto; + right: 0; + left: auto; + transform-origin: right center; +} + +::view-transition-old(figure-caption) { + animation: 0.25s linear both shrink-x; +} + +::view-transition-new(figure-caption) { + animation: 0.25s 0.25s linear both grow-x; +} +``` + +Here we've created a custom CSS animation and applied it to the `::view-transition-old(figure-caption)` and `::view-transition-new(figure-caption)` pseudo-elements. We've also added a number of other styles to both to keep them in the same place and stop the default styling from interfering with our custom animations. + +### Taking advantage of the default animation styles + +Note that we also discovered another transition option that is simpler and produced a nicer result than the above. Our final `
` view transition ended up looking like this: + +```css +figcaption { + view-transition-name: figure-caption; +} + +::view-transition-old(figure-caption), +::view-transition-new(figure-caption) { + height: 100%; +} +``` + +This works because, by default, `::view-transition-group` transitions `width` and `height` between the old and new views with a smooth scale. We just needed to set a fixed `height` on both states to make it work. + +> **Note:** [Smooth and simple transitions with the View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/) contains several other customization examples. + +## Controlling view transitions with JavaScript + +A view transition has an associated {{domxref("ViewTransition")}} object instance, which contains several promise members allowing you to run JavaScript in response to different states of the transition being reached. For example, {{domxref("ViewTransition.ready")}} fulfills once the pseudo-element tree is created and the animation is about to start, whereas {{domxref("ViewTransition.finished")}} fulfills once the animation is finished, and the new page view is visible and interactive to the user. + +The `ViewTransition` can be accessed like so: + +1. In the case of same-document (SPA) transitions, the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method returns the `ViewTransition` associated with the transition. +2. In the case of cross-document (MPA) transitions: + +- A {{domxref("Window.pageswap_event", "pageswap")}} event is fired when a document is about to be unloaded due to a navigation. Its event object ({{domxref("PageSwapEvent")}}) provides access to the `ViewTransition` via the {{domxref("PageSwapEvent.viewTransition")}} property, as well as a {{domxref("NavigationActivation")}} containing the navigation type and current and destination document history entries. +- A {{domxref("Window.pagereveal_event", "pagereveal")}} event is fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](https://web.dev/articles/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). Its event object ({{domxref("PageRevealEvent")}}) provides access to the `ViewTransition` via the {{domxref("PageRevealEvent.viewTransition")}} property. + +Let's have a look at some example code to show how these features could be used. + +### A JavaScript-powered custom same-document (SPA) transition + +The following JavaScript could be used to create a circular reveal view transition emanating from the position of the user's cursor on click, with animation provided by the {{domxref("Web Animations API", "Web Animations API", "", "nocode")}}. + +```js +// Store the last click event +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), + ); + + // Create 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)", + }, + ); + }); +} +``` + +This animation also requires the following CSS, to turn off the default CSS animation and stop the old and new view states from blending in any way (the new state "wipes" right over the top of the old state, rather than transitioning in): + +```css +::view-transition-image-pair(root) { + isolation: auto; +} + +::view-transition-old(root), +::view-transition-new(root) { + animation: none; + mix-blend-mode: normal; + display: block; +} +``` + +### A JavaScript-powered custom cross-document (MPA) transition + +To achieve the same circular reveal view transition during a cross-document navigation, multiple steps are required: + +1. Opt both pages in to cross-document view transitions using the {{cssxref("@view-transition")}} at rule, the same as we saw earlier: + + ```css + @view-transition { + navigation: auto; + } + ``` + +2. Store the mouse click location on the current page in [web storage](/en-US/docs/Web/API/Web_Storage_API) so that it can be retrieved by the destination page: + + ```js + addEventListener("click", (event) => { + sessionStorage.setItem("lastClickX", event.clientX); + sessionStorage.setItem("lastClickY", event.clientY); + }); + ``` + +3. Intercept the `ViewTransition` in the new document via the `pagereveal` event and use it to create the custom animation: + + ```js + // This would run both on initial load and on reactivation from BFCache. + addEventListener("pagereveal", async (event) => { + if (!event.viewTransition) return; + + const x = sessionStorage.getItem("lastClickX") ?? innerWidth / 2; + const y = sessionStorage.getItem("lastClickY") ?? innerHeight / 2; + + const endRadius = Math.hypot( + Math.max(x, innerWidth - x), + Math.max(y, innerHeight - y), + ); + + await event.viewTransition.ready; + + // Animate the new document's 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", + pseudoElement: "::view-transition-new(root)", + }, + ); + }); + ``` diff --git a/files/en-us/web/api/viewtransition/index.md b/files/en-us/web/api/viewtransition/index.md index 36b23d570e0a85f..324c247ee9353f4 100644 --- a/files/en-us/web/api/viewtransition/index.md +++ b/files/en-us/web/api/viewtransition/index.md @@ -11,7 +11,7 @@ browser-compat: api.ViewTransition The **`ViewTransition`** interface of the {{domxref("View Transitions API", "View Transitions API", "", "nocode")}} represents a view transition, and provides functionality to react to the transition reaching different states (e.g. ready to run the animation, or animation finished) or skip the transition altogether. -This object type is returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method. When `startViewTransition()` is invoked, a sequence of steps is followed as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process). This also explains when the different promises fulfill. +This object type is returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method. When `startViewTransition()` is invoked, a sequence of steps is followed as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_process). This also explains when the different promises fulfill. {{InheritanceDiagram}} diff --git a/files/en-us/web/css/_doublecolon_view-transition-group/index.md b/files/en-us/web/css/_doublecolon_view-transition-group/index.md index e35c5146060a29a..4f3da8da257ab02 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-group/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-group/index.md @@ -11,7 +11,7 @@ browser-compat: css.selectors.view-transition-group The **`::view-transition-group`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents a single view transition group. -During a view transition, `::view-transition-group` is included in the associated pseudo-element tree as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process). It is only ever a child of {{cssxref("::view-transition")}}, and has a {{cssxref("::view-transition-image-pair")}} as a child. +During a view transition, `::view-transition-group` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree). It is only ever a child of {{cssxref("::view-transition")}}, and has a {{cssxref("::view-transition-image-pair")}} as a child. `::view-transition-group` is given the following default styling in the UA stylesheet: diff --git a/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md b/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md index b2bddafa4617966..a4ecec8d64888c9 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md @@ -11,7 +11,7 @@ browser-compat: css.selectors.view-transition-image-pair The **`::view-transition-image-pair`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents a container for a [view transition's](/en-US/docs/Web/API/View_Transitions_API) "old" and "new" view states — before and after the transition. -During a view transition, `::view-transition-image-pair` is included in the associated pseudo-element tree as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process). It is only ever a child of a {{cssxref("::view-transition-group")}}. In terms of children, it can have a {{cssxref("::view-transition-new")}} or a {{cssxref("::view-transition-old")}}, or both. +During a view transition, `::view-transition-image-pair` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree). It is only ever a child of a {{cssxref("::view-transition-group")}}. In terms of children, it can have a {{cssxref("::view-transition-new")}} or a {{cssxref("::view-transition-old")}}, or both. `::view-transition-image-pair` is given the following default styling in the UA stylesheet: diff --git a/files/en-us/web/css/_doublecolon_view-transition-new/index.md b/files/en-us/web/css/_doublecolon_view-transition-new/index.md index ece636dfcc35b1c..a05cfe4a5be75a8 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-new/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-new/index.md @@ -11,7 +11,7 @@ browser-compat: css.selectors.view-transition-new The **`::view-transition-new`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the "new" view state of a view transition — a live representation of the new view, after the transition. -During a view transition, `::view-transition-new` is included in the associated pseudo-element tree as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process). It is only ever a child of a {{cssxref("::view-transition-image-pair")}}, and never has any children. +During a view transition, `::view-transition-new` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree). It is only ever a child of a {{cssxref("::view-transition-image-pair")}}, and never has any children. It is a replaced element, and therefore can be manipulated with properties such as {{cssxref("object-fit")}} and {{cssxref("object-position")}}. It has natural dimensions equal to the content's size. diff --git a/files/en-us/web/css/_doublecolon_view-transition-old/index.md b/files/en-us/web/css/_doublecolon_view-transition-old/index.md index 736763ce535e926..9c09bd39a89f8aa 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-old/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-old/index.md @@ -11,7 +11,7 @@ browser-compat: css.selectors.view-transition-old The **`::view-transition-old`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the "old" view state of a view transition — a static screenshot of the old view, before the transition. -During a view transition, `::view-transition-old` is included in the associated pseudo-element tree as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process), provided there's an "old" view state to represent. It is only ever a child of a {{cssxref("::view-transition-image-pair")}}, and never has any children. +During a view transition, `::view-transition-old` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree), provided there's an "old" view state to represent. It is only ever a child of a {{cssxref("::view-transition-image-pair")}}, and never has any children. It is a replaced element, and therefore can be manipulated with properties such as {{cssxref("object-fit")}} and {{cssxref("object-position")}}. It has natural dimensions equal to the content's size. diff --git a/files/en-us/web/css/_doublecolon_view-transition/index.md b/files/en-us/web/css/_doublecolon_view-transition/index.md index 0bd00af1a053401..c635fabf3524eeb 100644 --- a/files/en-us/web/css/_doublecolon_view-transition/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition/index.md @@ -11,7 +11,7 @@ browser-compat: css.selectors.view-transition The **`::view-transition`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the root of the [view transitions](/en-US/docs/Web/API/View_Transitions_API) overlay, which contains all view transitions and sits over the top of all other page content. -During a view transition, `::view-transition` is included in the associated pseudo-element tree as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API#the_view_transition_process). It is the top-level node of this tree, and has one or more {{cssxref("::view-transition-group")}}s as children. +During a view transition, `::view-transition` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree). It is the top-level node of this tree, and has one or more {{cssxref("::view-transition-group")}}s as children. `::view-transition` is given the following default styling in the UA stylesheet: diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index 3e5fb619b4df4c5..423e4fcba33a9d0 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -1700,10 +1700,16 @@ }, "View Transitions API": { "overview": ["View Transitions API"], - "interfaces": ["ViewTransition"], + "guides": ["/docs/Web/API/View_Transitions_API/Using"], + "interfaces": [ + "NavigationActivation", + "PageRevealEvent", + "PageSwapEvent", + "ViewTransition" + ], "methods": ["Document.startViewTransition()"], "properties": [], - "events": [] + "events": ["Window: pagereveal", "Window: pageswap"] }, "VirtualKeyboard API": { "overview": ["VirtualKeyboard API"], From 218ab88f62fac319fc3cb3a06dbe9707b6b545b6 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 18 Mar 2024 14:28:56 +0000 Subject: [PATCH 02/53] Add link rel=expect explanation --- .../web/api/view_transitions_api/index.md | 2 +- .../api/view_transitions_api/using/index.md | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index 91a234e13da04fa..c94f42b4f27e45a 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -54,7 +54,7 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us ## HTML additions - [``](/en-US/docs/Web/HTML/Attributes/rel#expect) - - : Identifies the most critical content in the associated document for the user's initial view of the page. Document rendering will be blocked until the critical content has been parsed, ensuring a consistent first paint (and therefore, view transition) across all supporting browsers. + - : Identifies the most critical content in the associated document for the user's initial view of the page. Document rendering will be blocked until the critical content has been parsed, ensuring a consistent first paint — and therefore, view transition — across all supporting browsers. ## CSS additions diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index ddc76d5f2f73f3a..b9984484d3a5fb0 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -378,3 +378,53 @@ To achieve the same circular reveal view transition during a cross-document navi ); }); ``` + +## Making cross-document view transitions consistent + +[``](/en-US/docs/Web/HTML/Attributes/rel#expect) allows you to specify the most critical content in the associated document for the user's initial view of the page. Document rendering can be blocked until the specified critical content has been parsed, avoiding layout shifts and flashes when loading, and ensuring a consistent first paint across all supporting browsers. This is important for view transitions — a different first paint could result in a vastly different transition animation. + +Let's explore how this works with a simple example HTML document: + +```html + + + + +

Page title

+ +
+
The first section
+
The second section
+
+ + +``` + +Note the `` line: + +```html + +``` + +- `rel="expect"` tells the browser that we are expecting to block a specific action on a particular part of the page being parsed. +- `href="#lead-content"` specifies the ID of the element we want to block on. In this case, we are blocking the action until the {{htmlelement("div")}} element and its contents have been parsed. +- [`blocking="render"`](/en-US/docs/Web/HTML/Attributes/rel#blocking) specifies that the action we will block is the rendering of the document. + +The result is that document rendering is blocked until the lead content `
` has been parsed, ensuring consistency in first paint and view transitions. + +You can also specify a [`media`](/en-US/docs/Web/HTML/Attributes/rel#blocking) attribute on `` elements. For example, you might want to block rendering on a smaller amount of content when loading the page on a narrow-screen device, than on a wide-screen device. This makes sense — on a mobile, less content will be visible when the page first loads than in the case of a desktop. + +This could be achieved with the following HTML: + +```html + + +``` From b82a640d33c7045a344a33fc5a5a9cc3bd1e0a90 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 19 Mar 2024 13:14:09 +0000 Subject: [PATCH 03/53] Update existing content to make sense for SPA and MPA transitions --- .../api/document/startviewtransition/index.md | 6 +++--- .../web/api/view_transitions_api/index.md | 12 +++++------ .../api/view_transitions_api/using/index.md | 19 ++++++++++------- .../web/api/viewtransition/finished/index.md | 8 +++---- files/en-us/web/api/viewtransition/index.md | 17 ++++++++++----- .../web/api/viewtransition/ready/index.md | 2 +- .../viewtransition/skiptransition/index.md | 21 ++++++++++++++++++- .../updatecallbackdone/index.md | 8 ++++--- .../index.md | 4 ++-- .../index.md | 2 +- .../_doublecolon_view-transition-new/index.md | 8 +++---- .../_doublecolon_view-transition-old/index.md | 6 +++--- .../web/css/view-transition-name/index.md | 2 +- 13 files changed, 74 insertions(+), 41 deletions(-) diff --git a/files/en-us/web/api/document/startviewtransition/index.md b/files/en-us/web/api/document/startviewtransition/index.md index 5a9abbf34400190..80a3e86d2413778 100644 --- a/files/en-us/web/api/document/startviewtransition/index.md +++ b/files/en-us/web/api/document/startviewtransition/index.md @@ -11,7 +11,7 @@ browser-compat: api.Document.startViewTransition {{APIRef("Document")}}{{SeeCompatTable}} The **`startViewTransition()`** method of the -{{domxref("View Transitions API", "View Transitions API", "", "nocode")}} starts a new view transition and returns a {{domxref("ViewTransition")}} object to represent it. +{{domxref("View Transitions API", "View Transitions API", "", "nocode")}} starts a new same-document (SPA) view transition and returns a {{domxref("ViewTransition")}} object to represent it. When `startViewTransition()` is invoked, a sequence of steps is followed as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_process). @@ -24,7 +24,7 @@ startViewTransition(callback) ### Parameters - `callback` - - : A callback function typically invoked to update the DOM during the view transition process, which returns a {{jsxref("Promise")}}. The callback is invoked once the API has taken a screenshot of the current page. When the promise returned by the callback fulfills, the view transition begins in the next frame. If the promise returned by the callback rejects, the transition is abandoned. + - : A callback function typically invoked to update the DOM during the SPA view transition process, which returns a {{jsxref("Promise")}}. The callback is invoked once the API has taken a screenshot of the current page. When the promise returned by the callback fulfills, the view transition begins in the next frame. If the promise returned by the callback rejects, the transition is abandoned. ### Return value @@ -34,7 +34,7 @@ A {{domxref("ViewTransition")}} object instance. ### Basic usage -In our [Basic View Transitions demo](https://mdn.github.io/dom-examples/view-transitions/), the `updateView()` function handles both browsers that do and don't support the View Transitions API. In supporting browsers, we invoke `startViewTransition()` to set off the view transition process without worrying about the return value. +In our [Basic SPA View Transitions demo](https://mdn.github.io/dom-examples/view-transitions/spa/), the `updateView()` function handles both browsers that do and don't support the View Transitions API. In supporting browsers, we invoke `startViewTransition()` to trigger the view transition process without worrying about the return value. ```js function updateView(event) { diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index c94f42b4f27e45a..18fa04b6b3f0414 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -45,10 +45,10 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us ## Extensions to other interfaces - {{domxref("Document.startViewTransition()")}} - - : Starts a new view transition and returns a {{domxref("ViewTransition")}} object to represent it. - The {{domxref("Window")}} {{domxref("Window.pagereveal_event", "pagereveal")}} event + - : Starts a new same-document (SPA) view transition and returns a {{domxref("ViewTransition")}} object to represent it. +- The {{domxref("Window")}} {{domxref("Window.pagereveal_event", "pagereveal")}} event - : Fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](https://web.dev/articles/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). - The {{domxref("Window")}} {{domxref("Window.pageswap_event", "pageswap")}} event +- The {{domxref("Window")}} {{domxref("Window.pageswap_event", "pageswap")}} event - : Fired when a document is about to be unloaded due to a navigation. ## HTML additions @@ -83,9 +83,9 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us ## Examples -- [Basic View Transitions SPA demo](https://mdn.github.io/dom-examples/view-transitions/spa/): A basic image gallery demo with separate transitions between old and new images, and old and new captions. -- [Basic View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transitions/mpa/): A sample two-page site that demonstrates usage of cross-document (MPA) view transitions, providing a smooth transition when the two pages are navigated between. -- [HTTP 203 playlist](https://http203-playlist.netlify.app/): A video player demo app that features a number of different SPA view transitions, many of which are explained in [Smooth and simple transitions with the View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/). +- [Basic View Transitions SPA demo](https://mdn.github.io/dom-examples/view-transitions/spa/): A basic image gallery demo with view transitions, featuring separate animations between old and new images, and old and new captions. +- [Basic View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transitions/mpa/): A sample two-page site that demonstrates usage of cross-document (MPA) view transitions, providing a custom "swipe up" transition when the two pages are navigated between. +- [HTTP 203 playlist](https://http203-playlist.netlify.app/): A video player demo app that features several different SPA view transitions, many of which are explained in [Smooth and simple transitions with the View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/). ## Specifications diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index b9984484d3a5fb0..54a87df3774f89b 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -20,11 +20,17 @@ Let's walk through the process by which a view transition works: > **Note:** An active view transition has an associated {{domxref("ViewTransition")}} instance (for example, returned by `startViewTransition()` in the case of same-document (SPA) transitions). The `ViewTransition` object includes several promises, allowing you to run code in response to different parts of the view transition process being reached. See [Controlling view transitions with JavaScript](#controlling_view_transitions_with_javascript) for mroe information. 2. The API takes a screenshot of the current (old page) view. 3. The view change occurs: + - In the case of same-document transitions (SPAs), the callback passed to `startViewTransition()` is invoked, which causes the DOM to change. - > **Note:** When the callback has run successfully, the {{domxref("ViewTransition.updateCallbackDone")}} promise fulfills, allowing you to respond to the DOM updating. + + When the callback has run successfully, the {{domxref("ViewTransition.updateCallbackDone")}} promise fulfills, allowing you to respond to the DOM updating. + - In the case of cross-document transitions (MPAs), the navigation occurs between the current and destination documents. + 4. The API captures the new view as a live representation. - > **Note:** At this point, the view transition is about to run, and the {{domxref("ViewTransition.ready")}} promise fulfills, allowing you to respond by running a custom JavaScript animation instead of the default, for example. + + At this point, the view transition is about to run, and the {{domxref("ViewTransition.ready")}} promise fulfills, allowing you to respond by running a custom JavaScript animation instead of the default, for example. + 5. The old page view animates "out", while the new view animates "in". By default, the old view animates from {{cssxref("opacity")}} 1 to 0 and the new view animates from `opacity` 0 to 1, which creates a cross-fade. 6. When the transition animation has reached its end state, the {{domxref("ViewTransition.finished")}} promise fulfills, allowing you to respond. @@ -40,7 +46,9 @@ To handle creating the outbound and inbound transition animations, the API const └─ ::view-transition-new(root) ``` -The most interesting parts of this structure are as follows: +In the case of same-document transitions (SPAs), the pseudo-element tree is made available in the document. In the case of cross-document transitions (MPAs), the pseudo-element tree is made available in both the current and destination documents. + +The most interesting parts of the tree structure are as follows: - {{cssxref("::view-transition")}} is the root of view transitions overlay, which contains all view transitions and sits over the top of all other page content. - {{cssxref("::view-transition-old")}} targets the screenshot of the old page view, and {{cssxref("::view-transition-new")}} targets the live representation of the new page view. Both of these render as replaced content, in the same manner as an {{htmlelement("img")}} or {{htmlelement("video")}}, meaning that they can be styled with handy properties like {{cssxref("object-fit")}} and {{cssxref("object-position")}}. @@ -48,9 +56,6 @@ The most interesting parts of this structure are as follows: > **Note:** As you'll see later, to customize the outbound and inbound animations you need to target the {{cssxref("::view-transition-old")}} and {{cssxref("::view-transition-new")}} pseudo-elements with your animations, respectively. -- In the case of same-document transitions (SPAs), the pseudo-element tree is made available in the document. -- In the case of cross-document transitions (MPAs), the pseudo-element tree is made available in both the current and destination documents. - ## Creating a basic view transition This section illustates how to create a basic view transition, in both the SPA and MPA case. @@ -101,7 +106,7 @@ Our [View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transiti The View Transitions pseudo-elements have default [CSS Animations](/en-US/docs/Web/CSS/CSS_animations) applied (which are detailed in their [reference pages](/en-US/docs/Web/API/View_Transitions_API#pseudo-elements)). -Most appearence transitions are given a default smooth cross-fade animation, as mentioned above. There are some exceptions: +Most appearance transitions are given a default smooth cross-fade animation, as mentioned above. There are some exceptions: - `height` and `width` transitions have a smooth scaling animation applied. - `position` and `transform` transitions have a smooth movement animation applied. diff --git a/files/en-us/web/api/viewtransition/finished/index.md b/files/en-us/web/api/viewtransition/finished/index.md index d936d3d476a0679..2e2e0af516de341 100644 --- a/files/en-us/web/api/viewtransition/finished/index.md +++ b/files/en-us/web/api/viewtransition/finished/index.md @@ -13,9 +13,9 @@ browser-compat: api.ViewTransition.finished The **`finished`** read-only property of the {{domxref("ViewTransition")}} interface is a {{jsxref("Promise")}} that fulfills once the transition animation is finished, and the new page view is visible and interactive to the user. -`finished` only rejects if the callback passed to {{domxref("Document.startViewTransition()", "document.startViewTransition()")}}throws or returns a promise that rejects, which indicates that the new state of the page wasn't created. +`finished` will only reject in the case of a same-document (SPA) transition, if the callback passed to {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} throws or returns a promise that rejects. This would indicate that the new state of the page wasn't created. -If a transition animation fails to start, or is skipped during the animation using {{domxref("ViewTransition.skipTransition()")}}, the end state is still reached therefore `finished` still fulfills. +If a transition animation fails to start or is skipped during the transition using {{domxref("ViewTransition.skipTransition()")}}, the end state is still reached therefore `finished` will still fulfill. ## Value @@ -25,7 +25,7 @@ A promise. ### Different transitions for different navigations -Sometimes certain navigations will require specifically tailored transitions, for example a 'back' navigation may want a different transition to a 'forward' navigation. The best way to handle such cases is to set a class name on the `` element, handle the transition — applying the correct animation using a tailored selector — and then remove the class name once the transition is finished. +Sometimes certain navigations will require specifically tailored transitions, for example, a 'back' navigation may want a different transition to a 'forward' navigation. The best way to handle such cases is to set a class name on the `` element, handle the transition — applying the correct animation using a tailored selector — and then remove the class name once the transition is finished. ```js async function handleTransition() { @@ -45,7 +45,7 @@ async function handleTransition() { } ``` -> **Note:** `isBackNavigation` isn't a built-in feature; it's a theoretical function that could perhaps be implemented using the [Navigation API](/en-US/docs/Web/API/Navigation_API) or similar. +> **Note:** `isBackNavigation` isn't a built-in feature; it's a theoretical function that could be implemented using the [Navigation API](/en-US/docs/Web/API/Navigation_API) or similar. ## Specifications diff --git a/files/en-us/web/api/viewtransition/index.md b/files/en-us/web/api/viewtransition/index.md index 324c247ee9353f4..610af7dfa42855d 100644 --- a/files/en-us/web/api/viewtransition/index.md +++ b/files/en-us/web/api/viewtransition/index.md @@ -9,9 +9,16 @@ browser-compat: api.ViewTransition {{APIRef("View Transitions API")}}{{SeeCompatTable}} -The **`ViewTransition`** interface of the {{domxref("View Transitions API", "View Transitions API", "", "nocode")}} represents a view transition, and provides functionality to react to the transition reaching different states (e.g. ready to run the animation, or animation finished) or skip the transition altogether. +The **`ViewTransition`** interface of the {{domxref("View Transitions API", "View Transitions API", "", "nocode")}} represents an active view transition, and provides functionality to react to the transition reaching different states (e.g. ready to run the animation, or animation finished) or skip the transition altogether. -This object type is returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method. When `startViewTransition()` is invoked, a sequence of steps is followed as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_process). This also explains when the different promises fulfill. +This object type is made available in the following ways: + +- In the same of same-document (SPA) transitions, it is returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method. +- In the case of cross-document (MPA) transitions, it is made available: + - In the outgoing page via the {{domxref("Window.pageswap_event", "pageswap")}} event object's {{domxref("PageSwapEvent.viewTransition")}} property. + - In the inbound page via the {{domxref("Window.pagereveal_event", "pagereveal")}} event object's {{domxref("PageRevealEvent.viewTransition")}} property. + +When a view transition is triggered by a `startViewTransition()` call (or a page navigation in the case of MPA transitions), a sequence of steps is followed as explained in [The view transition process](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_process). This also explains when the different promises fulfill. {{InheritanceDiagram}} @@ -22,16 +29,16 @@ This object type is returned by the {{domxref("Document.startViewTransition()", - {{domxref("ViewTransition.ready")}} {{Experimental_Inline}} - : A {{jsxref("Promise")}} that fulfills once the pseudo-element tree is created and the transition animation is about to start. - {{domxref("ViewTransition.updateCallbackDone")}} {{Experimental_Inline}} - - : A {{jsxref("Promise")}} that fulfills when the promise returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}}'s callback fulfills. + - : A {{jsxref("Promise")}} that fulfills when the promise returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method's callback fulfills. ## Instance methods - {{domxref("ViewTransition.skipTransition", "skipTransition()")}} {{Experimental_Inline}} - - : Skips the animation part of the view transition, but doesn't skip running the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} callback that updates the DOM. + - : Skips the animation part of the view transition, but doesn't skip running the associated view update. ## Examples -In the following example, the {{domxref("ViewTransition.ready")}} promise is used to trigger a custom circular reveal view transition emanating from the position of the user's cursor on click, with animation provided by the {{domxref("Web Animations API", "Web Animations API", "", "nocode")}}. +In the following SPA example, the {{domxref("ViewTransition.ready")}} promise is used to trigger a custom circular reveal view transition emanating from the position of the user's cursor on click, with animation provided by the {{domxref("Web Animations API", "Web Animations API", "", "nocode")}}. ```js // Store the last click event diff --git a/files/en-us/web/api/viewtransition/ready/index.md b/files/en-us/web/api/viewtransition/ready/index.md index 622c2abfd86be0c..4973b97dc1ed6f1 100644 --- a/files/en-us/web/api/viewtransition/ready/index.md +++ b/files/en-us/web/api/viewtransition/ready/index.md @@ -13,7 +13,7 @@ browser-compat: api.ViewTransition.ready The **`ready`** read-only property of the {{domxref("ViewTransition")}} interface is a {{jsxref("Promise")}} that fulfills once the pseudo-element tree is created and the transition animation is about to start. -`ready` will reject if the transition cannot begin. This can be due to misconfiguration, for example duplicate {{cssxref("view-transition-name")}}s, or if the callback passed to {{domxref("Document.startViewTransition()")}} throws or returns a promise that rejects. +`ready` will reject if the transition cannot begin. This can be due to misconfiguration, for example, duplicate {{cssxref("view-transition-name")}}s, or if the callback passed to {{domxref("Document.startViewTransition()")}} throws or returns a promise that rejects. ## Value diff --git a/files/en-us/web/api/viewtransition/skiptransition/index.md b/files/en-us/web/api/viewtransition/skiptransition/index.md index 2e2c7f8498ef99e..5701e99f0880b3a 100644 --- a/files/en-us/web/api/viewtransition/skiptransition/index.md +++ b/files/en-us/web/api/viewtransition/skiptransition/index.md @@ -11,7 +11,10 @@ browser-compat: api.ViewTransition.skipTransition {{APIRef("View Transitions API")}}{{SeeCompatTable}} The **`skipTransition()`** method of the -{{domxref("ViewTransition")}} interface skips the animation part of the view transition, but doesn't skip running the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} callback that updates the DOM. +{{domxref("ViewTransition")}} interface skips the animation part of the view transition, but doesn't skip running the associated view update. + +- In the case of a same-origin (SPA) transition, this would be triggered by the invocation of the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} callback that updates the DOM. +- In the case of a cross-origin (MPA) transition, this would be triggered by a page navigation. ## Syntax @@ -29,6 +32,8 @@ None. ## Examples +### Skipping an SPA view transition + ```js // start new view transition const transition = document.startViewTransition(() => displayNewImage()); @@ -37,6 +42,20 @@ const transition = document.startViewTransition(() => displayNewImage()); transition.skipTransition(); ``` +### Skipping an MPA view transition + +```js +// Fired on the current (outgoing) page +document.addEventListener("pageswap", (event) => { + event.viewTransition.skipTransition(); +}); + +// Fired on the destination (inbound) page +document.addEventListener("pagereveal", (event) => { + event.viewTransition.skipTransition(); +}); +``` + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/viewtransition/updatecallbackdone/index.md b/files/en-us/web/api/viewtransition/updatecallbackdone/index.md index da85c39ae64357d..efd1344d6218020 100644 --- a/files/en-us/web/api/viewtransition/updatecallbackdone/index.md +++ b/files/en-us/web/api/viewtransition/updatecallbackdone/index.md @@ -11,9 +11,11 @@ browser-compat: api.ViewTransition.updateCallbackDone {{APIRef("View Transitions API")}}{{SeeCompatTable}} The **`updateCallbackDone`** read-only property of the -{{domxref("ViewTransition")}} interface is a {{jsxref("Promise")}} that fulfills when the promise returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}}'s callback fulfills, or rejects when it rejects. +{{domxref("ViewTransition")}} interface is a {{jsxref("Promise")}} that fulfills when the promise returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method's callback fulfills, or rejects when it rejects. -`updateCallbackDone` is useful when you don't care about the success/failure of the transition animation, and just want to know if and when the DOM is updated. +`updateCallbackDone` is useful when you don't care about the success/failure of a same-document (SPA) view transition animation, and just want to know if and when the DOM is updated. + +> **Note:** In the case of a cross-document (MPA) view transition, the `updateCallbackDone` promise of the associated `ViewTransition` is automatically fulfilled. ## Value @@ -22,7 +24,7 @@ A promise. ## Examples ```js -// start new view transition +// start new SPA view transition const transition = document.startViewTransition(() => displayNewImage()); transition.updateCallbackDone.then(() => { diff --git a/files/en-us/web/css/_doublecolon_view-transition-group/index.md b/files/en-us/web/css/_doublecolon_view-transition-group/index.md index 4f3da8da257ab02..93a0cf19c8436e2 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-group/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-group/index.md @@ -30,7 +30,7 @@ By default, selected elements initially mirror the size and position of the {{cs If there's both an "old" and "new" view state, styles in the view transition style sheet animate this pseudo-element's {{cssxref("width")}} and {{cssxref("height")}} from the size of the "old" view state's border box to that of the "new" view state's border box. -> **Note:** View transition style sheet styles are dynamically generated during the view transition; see the specification [setup transition pseudo-elements](https://drafts.csswg.org/css-view-transitions-1/#setup-transition-pseudo-elements) and [update pseudo-element styles](https://drafts.csswg.org/css-view-transitions-1/#update-pseudo-element-styles) sections for more details. +> **Note:** View transition styles are dynamically generated during the view transition; see the specification [setup transition pseudo-elements](https://drafts.csswg.org/css-view-transitions-1/#setup-transition-pseudo-elements) and [update pseudo-element styles](https://drafts.csswg.org/css-view-transitions-1/#update-pseudo-element-styles) sections for more details. In addition, the element's transform is animated from the "old" view state's screen space transform to the new view state's screen space transform. This style is generated dynamically since the values of animated properties are determined at the time that the transition begins. @@ -47,7 +47,7 @@ In addition, the element's transform is animated from the "old" view state's scr - `*` - : Causes the pseudo-element to match all view transition groups. - `root` - - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page, meaning any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. + - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page. This group includes any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. - {{cssxref("custom-ident")}} - : Causes the pseudo-element to match a specific view transition group created by assigning the given {{cssxref("custom-ident")}} to an element via the {{cssxref("view-transition-name")}} property. diff --git a/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md b/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md index a4ecec8d64888c9..cd20c0ecf09aef6 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md @@ -40,7 +40,7 @@ During a view transition, `::view-transition-image-pair` has {{cssxref("isolatio - `*` - : Causes the pseudo-element to match all view transition groups. - `root` - - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page, meaning any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. + - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page. This group includes any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. - {{cssxref("custom-ident")}} - : Causes the pseudo-element to match a specific view transition group created by assigning the given {{cssxref("custom-ident")}} to an element via the {{cssxref("view-transition-name")}} property. diff --git a/files/en-us/web/css/_doublecolon_view-transition-new/index.md b/files/en-us/web/css/_doublecolon_view-transition-new/index.md index a05cfe4a5be75a8..6e3a4a80c4519a6 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-new/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-new/index.md @@ -9,11 +9,11 @@ browser-compat: css.selectors.view-transition-new {{CSSRef}}{{SeeCompatTable}} -The **`::view-transition-new`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the "new" view state of a view transition — a live representation of the new view, after the transition. +The **`::view-transition-new`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the "new" view state of a view transition — a live representation of the state after the transition. During a view transition, `::view-transition-new` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree). It is only ever a child of a {{cssxref("::view-transition-image-pair")}}, and never has any children. -It is a replaced element, and therefore can be manipulated with properties such as {{cssxref("object-fit")}} and {{cssxref("object-position")}}. It has natural dimensions equal to the content's size. +It is a replaced element and therefore can be manipulated with properties such as {{cssxref("object-fit")}} and {{cssxref("object-position")}}. It has natural dimensions equal to the content's size. The following default styling is included in the UA stylesheet: @@ -36,7 +36,7 @@ html::view-transition-new(*) { } ``` -> **Note:** Additional view transition style sheet styles are also setup to animate `::view-transition-new`. These are dynamically generated during the view transition; see the specification [setup transition pseudo-elements](https://drafts.csswg.org/css-view-transitions-1/#setup-transition-pseudo-elements) and [update pseudo-element styles](https://drafts.csswg.org/css-view-transitions-1/#update-pseudo-element-styles) sections for more details. +> **Note:** Additional view transition styles are also setup to animate `::view-transition-new`. These are dynamically generated during the view transition; see the specification [setup transition pseudo-elements](https://drafts.csswg.org/css-view-transitions-1/#setup-transition-pseudo-elements) and [update pseudo-element styles](https://drafts.csswg.org/css-view-transitions-1/#update-pseudo-element-styles) sections for more details. ## Syntax @@ -51,7 +51,7 @@ html::view-transition-new(*) { - `*` - : Causes the pseudo-element to match all view transition groups. - `root` - - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page, meaning any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. + - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page. This group includes any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. - {{cssxref("custom-ident")}} - : Causes the pseudo-element to match a specific view transition group created by assigning the given {{cssxref("custom-ident")}} to an element via the {{cssxref("view-transition-name")}} property. diff --git a/files/en-us/web/css/_doublecolon_view-transition-old/index.md b/files/en-us/web/css/_doublecolon_view-transition-old/index.md index 9c09bd39a89f8aa..8f0a2c54386ecde 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-old/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-old/index.md @@ -13,7 +13,7 @@ The **`::view-transition-old`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en- During a view transition, `::view-transition-old` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree), provided there's an "old" view state to represent. It is only ever a child of a {{cssxref("::view-transition-image-pair")}}, and never has any children. -It is a replaced element, and therefore can be manipulated with properties such as {{cssxref("object-fit")}} and {{cssxref("object-position")}}. It has natural dimensions equal to the content's size. +It is a replaced element and therefore can be manipulated with properties such as {{cssxref("object-fit")}} and {{cssxref("object-position")}}. It has natural dimensions equal to the content's size. The following default styling is included in the UA stylesheet: @@ -36,7 +36,7 @@ html::view-transition-old(*) { } ``` -> **Note:** Additional view transition style sheet styles are also setup to animate `::view-transition-old`. These are dynamically generated during the view transition; see the specification [setup transition pseudo-elements](https://drafts.csswg.org/css-view-transitions-1/#setup-transition-pseudo-elements) and [update pseudo-element styles](https://drafts.csswg.org/css-view-transitions-1/#update-pseudo-element-styles) sections for more details. +> **Note:** Additional view transition styles are also setup to animate `::view-transition-old`. These are dynamically generated during the view transition; see the specification [setup transition pseudo-elements](https://drafts.csswg.org/css-view-transitions-1/#setup-transition-pseudo-elements) and [update pseudo-element styles](https://drafts.csswg.org/css-view-transitions-1/#update-pseudo-element-styles) sections for more details. ## Syntax @@ -51,7 +51,7 @@ html::view-transition-old(*) { - `*` - : Causes the pseudo-element to match all view transition groups. - `root` - - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page, meaning any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. + - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page. This group includes any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. - {{cssxref("custom-ident")}} - : Causes the pseudo-element to match a specific view transition group created by assigning the given {{cssxref("custom-ident")}} to an element via the {{cssxref("view-transition-name")}} property. diff --git a/files/en-us/web/css/view-transition-name/index.md b/files/en-us/web/css/view-transition-name/index.md index 7bb22beb3830642..76c994bf2760ecb 100644 --- a/files/en-us/web/css/view-transition-name/index.md +++ b/files/en-us/web/css/view-transition-name/index.md @@ -25,7 +25,7 @@ view-transition-name: none; ### Values - {{cssxref("custom-ident")}} - - : A distinct identifying name that causes the selected element to participate in a separate [view transition](/en-US/docs/Web/API/View_Transitions_API) from the root view transition. The identifier must be unique. If two rendered elements have the same `view-transition-name` at the same time, {{domxref("ViewTransition.ready")}} will reject and the transition will be skipped. + - : An identifying name that causes the selected element to participate in a separate [view transition](/en-US/docs/Web/API/View_Transitions_API) from the root view transition. The identifier must be unique. If two rendered elements have the same `view-transition-name` at the same time, {{domxref("ViewTransition.ready")}} will reject and the transition will be skipped. - `none` - : The selected element will not participate in a view transition. From 000fa7871d8742604b5da8c99d6d7b46017fdde7 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 19 Mar 2024 13:46:25 +0000 Subject: [PATCH 04/53] Add doc for @view-transition at-rule --- .../web/api/view_transitions_api/index.md | 2 +- .../api/view_transitions_api/using/index.md | 2 +- files/en-us/web/css/@view-transition/index.md | 58 +++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 files/en-us/web/css/@view-transition/index.md diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index 18fa04b6b3f0414..fc1257a1a1c6237 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -61,7 +61,7 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us ### At-rules - {{cssxref("@view-transition")}} - - : Used to opt in the current and destination documents to undergoing a view transition, in the case of a cross-document navigation. + - : In the case of a cross-document navigation, `@view-transition` is used to opt in the current and destination documents to undergo a view transition. ### Properties diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 54a87df3774f89b..568923088614094 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -90,7 +90,7 @@ This code is enough to handle the transition between displayed images. Supportin ### Basic MPA view transition -When creating a cross-document (MPA) view transition, the process is even simpler than for SPAs — no JavaScript is required, as the view update is triggered by a document navigation rather than a JavaScript-initiated DOM change. To enable a basic MPA view transition, you need to specify a {{cssxref("@view-transition")}} at rule in the CSS for both the current and destination documents to opt them in, like so: +When creating a cross-document (MPA) view transition, the process is even simpler than for SPAs — no JavaScript is required, as the view update is triggered by a document navigation rather than a JavaScript-initiated DOM change. To enable a basic MPA view transition, you need to specify a {{cssxref("@view-transition")}} at-rule in the CSS for both the current and destination documents to opt them in, like so: ```css @view-transition { diff --git a/files/en-us/web/css/@view-transition/index.md b/files/en-us/web/css/@view-transition/index.md new file mode 100644 index 000000000000000..cccd7aee307d726 --- /dev/null +++ b/files/en-us/web/css/@view-transition/index.md @@ -0,0 +1,58 @@ +--- +title: "@view-transition" +slug: Web/CSS/@view-transition +page-type: css-at-rule +browser-compat: css.at-rules.view-transition +--- + +{{CSSRef}} + +The **`@view-transition`** [CSS](/en-US/docs/Web/CSS) [at-rule](/en-US/docs/Web/CSS/At-rule) is used to opt in the current and destination documents to undergo a [view transition](/en-US/docs/Web/API/View_Transitions_API), in the case of a cross-document navigation. + +## Syntax + +```css +@view-transition { + navigation: auto; +} +``` + +### Descriptors + +- `navigation` + + - : Specifies the effect this at-rule will have on the document's view transition behavior. Possible values are: + + - `auto`: The document will undergo a view transition when taking part in a navigation, provided the navigation is same-origin, without cross-origin redirects, and its {{domxref("NavigateEvent.navigationType", "navigationType")}} is `traverse`, `push`, or `replace`. In the case of `replace`, the navigation must be initiated by a user interacting with the page content, not by a browser UI feature. + + - `none`: The document will not undergo a view transition. + +## Formal syntax + +{{csssyntax}} + +## Examples + +### Basic usage + +```css +@view-transition { + navigation: auto; +} +``` + +You need to specify the above `@view-transition` at-rule in the CSS for both the current and destination documents of a navigation to opt them in to the view transition. + +> **Note:** Our [View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transitions/mpa/) shows this at-rule in action, and additionally demonstrates how to customize the outbound and inbound animations of the view transition. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) From d8917799157736915f5c42481021bc28253a8755 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 20 Mar 2024 11:23:08 +0000 Subject: [PATCH 05/53] Add rel=expect content --- .../web/api/view_transitions_api/using/index.md | 4 ++-- files/en-us/web/html/attributes/rel/index.md | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 568923088614094..b00508f0bfb3532 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -384,9 +384,9 @@ To achieve the same circular reveal view transition during a cross-document navi }); ``` -## Making cross-document view transitions consistent +## Making cross-document transitions consistent with `rel="expect"` -[``](/en-US/docs/Web/HTML/Attributes/rel#expect) allows you to specify the most critical content in the associated document for the user's initial view of the page. Document rendering can be blocked until the specified critical content has been parsed, avoiding layout shifts and flashes when loading, and ensuring a consistent first paint across all supporting browsers. This is important for view transitions — a different first paint could result in a vastly different transition animation. +[``](/en-US/docs/Web/HTML/Attributes/rel#expect) allows you to specify the most critical content in the associated document for the user's initial view of the page. Document rendering can be blocked until the specified content has been parsed, avoiding layout shifts and flashes when loading, and ensuring a consistent first paint across all supporting browsers. This is important for view transitions — a different first paint could result in a vastly different transition animation. Let's explore how this works with a simple example HTML document: diff --git a/files/en-us/web/html/attributes/rel/index.md b/files/en-us/web/html/attributes/rel/index.md index 4e9fb7ebca8751a..e651b10785aad63 100644 --- a/files/en-us/web/html/attributes/rel/index.md +++ b/files/en-us/web/html/attributes/rel/index.md @@ -24,6 +24,7 @@ The following table lists some of the most important existing keywords. Every ke | [`canonical`](#canonical) | Preferred URL for the current document. | Link | Not allowed | Not allowed | | [`dns-prefetch`](/en-US/docs/Web/HTML/Attributes/rel/dns-prefetch) | Tells the browser to preemptively perform DNS resolution for the target resource's origin. | External Resource | Not allowed | Not allowed | | [`external`](#external) | The referenced document is not part of the same site as the current document. | Not allowed | Annotation | Annotation | +| [`expect`](#expect) | Specifies content critical for the user's initial view of the page. Document rendering can be blocked until the specified content has been parsed. | Link | Not allowed | Not allowed | | [`help`](#help) | Link to context-sensitive help. | Link | Link | Link | | [`icon`](#icon) | An icon representing the current document. | External Resource | Not allowed | Not allowed | | [`license`](#license) | Indicates that the main content of the current document is covered by the copyright license described by the referenced document. | Link | Link | Link | @@ -118,6 +119,22 @@ The `rel` attribute has no default value. If the attribute is omitted or if none - : Valid for {{htmlelement('link')}}, it defines the preferred URL for the current document, which helps search engines reduce duplicate content. - `dns-prefetch` - : Relevant for the {{htmlelement('link')}} element both in the {{htmlelement('body')}} and {{htmlelement('head')}}, it tells the browser to preemptively perform DNS resolution for the target resource's origin. Useful for resources the user will likely need, it helps reduce latency and thereby improves performance when the user does access the resources as the browser preemptively performed DNS resolution for the origin of the specified resource. See [dns-prefetch](/en-US/docs/Web/Performance/dns-prefetch) described in [resource hints](https://w3c.github.io/resource-hints/). +- `expect` + + - : `` allows you to specify the most critical content in the associated document for the user's initial view of the page. Document rendering can be blocked until the specified content has been parsed, avoiding layout shifts and flashes when loading, and ensuring a consistent first paint across all supporting browsers. This is important for [view transitions](/en-US/docs/Web/API/View_Transitions_API) — a different first paint could result in a vastly different transition animation. + + A typical example is as follows: + + ```html + + ``` + + - `rel="expect"` tells the browser that we are expecting to block a specific action on a particular part of the page being parsed. + - [`href="#lead-content"`](/en-US/docs/Web/HTML/Element/link#href) specifies the ID of the element we want to block on. In this case, we are blocking the action until the element with an `id` of `lead-content` and its contents have been parsed. + - [`blocking="render"`](/en-US/docs/Web/HTML/Element/link#blocking) specifies that the action we will block is the rendering of the document. + + See [Making cross-document transitions consistent with `rel="expect"`](/en-US/docs/Web/API/View_Transitions_API/Using#making_cross-document_transitions_consistent_with_relexpect) for a complete example. + - `external` - : Relevant to {{htmlelement('form')}}, {{htmlelement('a')}}, and {{htmlelement('area')}}, it indicates the referenced document is not part of the current site. This can be used with attribute selectors to style external links in a way that indicates to the user that they will be leaving the current site. - `help` From 30accf7dbd131c768f2777801de5d3ff2fca2f02 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 21 Mar 2024 14:14:49 +0000 Subject: [PATCH 06/53] Add pagereveal and pageswap event pages --- files/en-us/web/api/window/index.md | 4 + .../web/api/window/pagereveal_event/index.md | 60 ++++++++++++++ .../web/api/window/pageswap_event/index.md | 82 +++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 files/en-us/web/api/window/pagereveal_event/index.md create mode 100644 files/en-us/web/api/window/pageswap_event/index.md diff --git a/files/en-us/web/api/window/index.md b/files/en-us/web/api/window/index.md index 356cfe322b1f854..48a733336ca805a 100644 --- a/files/en-us/web/api/window/index.md +++ b/files/en-us/web/api/window/index.md @@ -346,8 +346,12 @@ Listen to these events using [`addEventListener()`](/en-US/docs/Web/API/EventTar - : Fired when the fragment identifier of the URL has changed (the part of the URL beginning with and following the `#` symbol). - {{domxref("Window/pagehide_event", "pagehide")}} - : Sent when the browser hides the current document while in the process of switching to displaying in its place a different document from the session's history. This happens, for example, when the user clicks the Back button or when they click the Forward button to move ahead in session history. +- {{domxref("Window.pagereveal_event", "pagereveal")}} {{experimental_inline}} + - : Fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](https://web.dev/articles/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). - {{domxref("Window/pageshow_event", "pageshow")}} - : Sent when the browser makes the document visible due to navigation tasks, including not only when the page is first loaded, but also situations such as the user navigating back to the page after having navigated to another within the same tab. +- {{domxref("Window.pageswap_event", "pageswap")}} {{experimental_inline}} + - : Fired when a document is about to be unloaded due to a navigation. - {{domxref("Window/popstate_event", "popstate")}} - : Fired when the active history entry changes. diff --git a/files/en-us/web/api/window/pagereveal_event/index.md b/files/en-us/web/api/window/pagereveal_event/index.md new file mode 100644 index 000000000000000..323d7e14649ef10 --- /dev/null +++ b/files/en-us/web/api/window/pagereveal_event/index.md @@ -0,0 +1,60 @@ +--- +title: "Window: pagereveal event" +short-title: pagereveal +slug: Web/API/Window/pagereveal_event +page-type: web-api-event +status: + - experimental +browser-compat: api.Window.pagereveal_event +--- + +{{APIRef("HTML DOM")}}{{seecompattable}} + +The **`pagereveal`** event is fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](https://web.dev/articles/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). + +This is useful in the case of cross-document (MPA) [view transitions](/en-US/docs/Web/API/View_Transitions_API) for manipulating an active transition from the inbound page of a navigation. For example, you might wish to skip the transition, or customize the inbound transition animation via JavaScript. + +## Syntax + +Use the event name in methods like {{domxref("EventTarget.addEventListener", "addEventListener()")}}, or set an event handler property. + +```js +addEventListener("pagereveal", (event) => {}); +onpagereveal = (event) => {}; +``` + +## Event type + +A {{domxref("PageRevealEvent")}}. Inherits from {{domxref("Event")}}. + +{{InheritanceDiagram("PageRevealEvent")}} + +## Event properties + +- {{domxref("PageRevealEvent.viewTransition")}} {{ReadOnlyInline}} + - : Returns the {{domxref("ViewTransition")}} object representing the inbound cross-document view transition, if one is active when the event is fired. If this is not the case, it returns `null`. + +## Examples + +```js +// This would run both on initial load and on reactivation from BFCache. +addEventListener("pagereveal", async (event) => { + // Skip the transition + event.viewTransition.skipTransition(); +}); +``` + +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Using) +- {{domxref("Window.pageswap_event", "pageswap")}} event diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md new file mode 100644 index 000000000000000..4541e11c071375b --- /dev/null +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -0,0 +1,82 @@ +--- +title: "Window: pageswap event" +short-title: pageswap +slug: Web/API/Window/pageswap_event +page-type: web-api-event +status: + - experimental +browser-compat: api.Window.pageswap_event +--- + +{{APIRef("HTML DOM")}}{{seecompattable}} + +The **`pageswap`** event is fired when a document is about to be unloaded due to a navigation. + +This is useful in the case of cross-document (MPA) [view transitions](/en-US/docs/Web/API/View_Transitions_API) for manipulating an active transition from the outbound page of a navigation. For example, you might wish to skip the transition, or customize the outbound transition animation via JavaScript. + +It also provides access to the navigation type and current and destination document history entries. + +## Syntax + +Use the event name in methods like {{domxref("EventTarget.addEventListener", "addEventListener()")}}, or set an event handler property. + +```js +addEventListener("pageswap", (event) => {}); +onpageswap = (event) => {}; +``` + +## Event type + +A {{domxref("PageSwapEvent")}}. Inherits from {{domxref("Event")}}. + +{{InheritanceDiagram("PageSwapEvent")}} + +## Event properties + +- {{domxref("PageSwapEvent.activation")}} {{ReadOnlyInline}} + - : Returns a {{domxref("NavigationActivation")}} object containing the navigation type and current and destination document history entries for a same-origin navigation. If the navigation is cross-origin, it returns `null`. +- {{domxref("PageSwapEvent.viewTransition")}} {{ReadOnlyInline}} + - : Returns the {{domxref("ViewTransition")}} object representing the inbound cross-document view transition, if one is active when the event is fired. If this is not the case, it returns `null`. + +## Examples + +```js +window.addEventListener("pageswap", (event) => { + // Return if there is no active view transition + if (!event.viewTransition) { + return; + } + + // Grab the paths of the from and to URLs + const from_path = new URL(event.activation.from).pathname; + const to_path = new URL(event.activation.entry).pathname; + + // Skip transitions from landing to home + if (from_path === "/landing" && to_path === "/home") { + event.viewTransition.skipTransition(); + } + + // Apply a different style when going "back" + const is_back = + event.activation.navigationType === "traverse" && + event.activation.entry?.index === event.activation.from?.index - 1; + + // Add a class to the element for targetting a different back animation + // Note that this would only apply to capturing the final state of the old document, + // The new document would have to do this or something similar in `pagereveal`. + document.documentElement.classList.toggle("back-nav", is_back); +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Using) +- {{domxref("Window.pagereveal_event", "pagereveal")}} event From 30eb72da75a0962ca8d20ca059e61d54993ba6ac Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 22 Mar 2024 14:53:57 +0000 Subject: [PATCH 07/53] Add docs for NavigationActivation --- files/en-us/web/api/navigation_api/index.md | 2 + .../api/navigationactivation/entry/index.md | 36 ++++++++++ .../api/navigationactivation/from/index.md | 37 +++++++++++ .../web/api/navigationactivation/index.md | 66 +++++++++++++++++++ .../navigationType/index.md | 39 +++++++++++ .../web/api/view_transitions_api/index.md | 2 +- files/jsondata/GroupData.json | 12 ++-- 7 files changed, 186 insertions(+), 8 deletions(-) create mode 100644 files/en-us/web/api/navigationactivation/entry/index.md create mode 100644 files/en-us/web/api/navigationactivation/from/index.md create mode 100644 files/en-us/web/api/navigationactivation/index.md create mode 100644 files/en-us/web/api/navigationactivation/navigationType/index.md diff --git a/files/en-us/web/api/navigation_api/index.md b/files/en-us/web/api/navigation_api/index.md index 3fe25516a83fc62..da09e490ea75c09 100644 --- a/files/en-us/web/api/navigation_api/index.md +++ b/files/en-us/web/api/navigation_api/index.md @@ -90,6 +90,8 @@ There are a few perceived limitations with the Navigation API: - : Event object for the {{domxref("Navigation/navigate_event", "navigate")}} event, which fires when [any type of navigation](https://github.com/WICG/navigation-api#appendix-types-of-navigations) is initiated. It provides access to information about that navigation, and most notably the {{domxref("NavigateEvent.intercept", "intercept()")}}, which allows you to control what happens when the navigation is initiated. - {{domxref("Navigation")}} {{Experimental_Inline}} - : Allows control over all navigation actions for the current `window` in one central place, including initiating navigations programmatically, examining navigation history entries, and managing navigations as they happen. +- {{domxref("NavigationActivation")}} + - : Represents a recent cross-document navigation. It contains the navigation type and current and destination document history entries. - {{domxref("NavigationCurrentEntryChangeEvent")}} {{Experimental_Inline}} - : Event object for the {{domxref("Navigation/currententrychange_event", "currententrychange")}} event, which fires when the {{domxref("Navigation.currentEntry")}} has changed. It provides access to the navigation type, and the previous history entry that was navigated from. - {{domxref("NavigationDestination")}} {{Experimental_Inline}} diff --git a/files/en-us/web/api/navigationactivation/entry/index.md b/files/en-us/web/api/navigationactivation/entry/index.md new file mode 100644 index 000000000000000..a3e70eb315798da --- /dev/null +++ b/files/en-us/web/api/navigationactivation/entry/index.md @@ -0,0 +1,36 @@ +--- +title: "NavigationActivation: entry property" +short-title: entry +slug: Web/API/NavigationActivation/entry +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.NavigationActivation.entry +--- + +{{APIRef("Navigation API")}}{{SeeCompatTable}} + +The **`entry`** read-only property of the {{domxref("NavigationActivation")}} interface contains a {{domxref("NavigationHistoryEntry")}} object representing the history entry for the inbound ("to") document in the navigation. This is equivalent to the {{domxref("Navigation.currentEntry")}} property at the moment the inbound document was activated. + +There are some cases in which either the from or entry NavigationHistoryEntry objects would not be viable targets for the traverseTo() method, as they might not be retained in history. For example, the Document can be activated using location.replace() or its initial entry could be replaced by history.replaceState(). However, those entries' url property and getState() method are still accessible. + +## Value + +A {{domxref("NavigationHistoryEntry")}} object. + +## Examples + +See the main {{domxref("NavigationActivation")}} reference page for an example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Navigation API](/en-US/docs/Web/API/Navigation_API) +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/navigationactivation/from/index.md b/files/en-us/web/api/navigationactivation/from/index.md new file mode 100644 index 000000000000000..34fd6182cb82c50 --- /dev/null +++ b/files/en-us/web/api/navigationactivation/from/index.md @@ -0,0 +1,37 @@ +--- +title: "NavigationActivation: from property" +short-title: from +slug: Web/API/NavigationActivation/from +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.NavigationActivation.from +--- + +{{APIRef("Navigation API")}}{{SeeCompatTable}} + +The **`from`** read-only property of the {{domxref("NavigationActivation")}} interface contains a {{domxref("NavigationHistoryEntry")}} object representing the history entry for the outgoing ("from") document in the navigation. + +## Value + +A {{domxref("NavigationHistoryEntry")}} object, or `null` if the outgoing document is: + +- Not same origin as the inbound document. +- The initial `about:blank` document. + +## Examples + +See the main {{domxref("NavigationActivation")}} reference page for an example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Navigation API](/en-US/docs/Web/API/Navigation_API) +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/navigationactivation/index.md b/files/en-us/web/api/navigationactivation/index.md new file mode 100644 index 000000000000000..886013a4c748064 --- /dev/null +++ b/files/en-us/web/api/navigationactivation/index.md @@ -0,0 +1,66 @@ +--- +title: NavigationActivation +slug: Web/API/NavigationActivation +page-type: web-api-interface +status: + - experimental +browser-compat: api.NavigationActivation +--- + +{{APIRef("Navigation API")}}{{SeeCompatTable}} + +The **`NavigationActivation`** interface of the [Navigation API](/en-US/docs/Web/API/Navigation_API) represents a recent cross-document navigation. It contains the navigation type and outgoing and inbound document history entries. + +This object is accessed via the {{domxref("PageSwapEvent.activation")}} and {{domxref("Navigation.activation")}} properties. + +## Instance properties + +- {{domxref("NavigationActivation.entry", "entry")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : Contains a {{domxref("NavigationHistoryEntry")}} object representing the history entry for the inbound ("to") document in the navigation. This is equivalent to the {{domxref("Navigation.currentEntry")}} property at the moment the inbound document was activated. +- {{domxref("NavigationActivation.from", "from")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : Contains a {{domxref("NavigationHistoryEntry")}} object representing the history entry for the outgoing ("from") document in the navigation. +- {{domxref("NavigationActivation.navigationType", "navigationType")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : Contains a string indicating the type of navigation. + +## Examples + +```js +window.addEventListener("pageswap", (event) => { + // Return if there is no active view transition + if (!event.viewTransition) { + return; + } + + // Grab the paths of the from and to URLs + const from_path = new URL(event.activation.from).pathname; + const to_path = new URL(event.activation.entry).pathname; + + // Skip transitions from landing to home + if (from_path === "/landing" && to_path === "/home") { + event.viewTransition.skipTransition(); + } + + // Apply a different style when going "back" + const is_back = + event.activation.navigationType === "traverse" && + event.activation.entry?.index === event.activation.from?.index - 1; + + // Add a class to the element for targetting a different back animation + // Note that this would only apply to capturing the final state of the old document, + // The new document would have to do this or something similar in `pagereveal`. + document.documentElement.classList.toggle("back-nav", is_back); +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Navigation API](/en-US/docs/Web/API/Navigation_API) +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/navigationactivation/navigationType/index.md b/files/en-us/web/api/navigationactivation/navigationType/index.md new file mode 100644 index 000000000000000..74ff34fc4bb07d0 --- /dev/null +++ b/files/en-us/web/api/navigationactivation/navigationType/index.md @@ -0,0 +1,39 @@ +--- +title: "NavigationActivation: navigationType property" +short-title: navigationType +slug: Web/API/NavigationActivation/navigationType +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.NavigationActivation.navigationType +--- + +{{APIRef("Navigation API")}}{{SeeCompatTable}} + +The **`navigationType`** read-only property of the {{domxref("NavigationActivation")}} interface contains a string indicating the type of navigation. + +## Value + +A string representing the type of navigation the {{domxref("NavigationActivation")}} relates to. Possible values are: + +- `push`: A new location was navigated to, causing a new entry to be pushed onto the history list. +- `reload`: The {{domxref("Navigation.currentEntry")}} was reloaded. +- `replace`: The {{domxref("Navigation.currentEntry")}} was replaced with a new history entry. This new entry will reuse the same {{domxref("NavigationHistoryEntry.key", "key")}}, but be assigned a different {{domxref("NavigationHistoryEntry.id", "id")}}. +- `traverse`: The browser navigated from one existing history entry to another existing history entry. + +## Examples + +See the main {{domxref("NavigationActivation")}} reference page for an example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Navigation API](/en-US/docs/Web/API/Navigation_API) +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index fc1257a1a1c6237..a35423cd16b24d9 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -34,7 +34,7 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us ## Interfaces - {{domxref("NavigationActivation")}} - - : Represents a cross-document navigation; contains the navigation type and current and destination document history entries. + - : Represents a recent cross-document navigation. It contains the navigation type and current and destination document history entries. - {{domxref("PageRevealEvent")}} - : The event object for the {{domxref("Window.pagereveal_event", "pagereveal")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. - {{domxref("PageSwapEvent")}} diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index 71a54feb256e9ea..d0d1721c4900d33 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -1011,10 +1011,13 @@ "interfaces": [ "NavigateEvent", "Navigation", + "NavigationActivation", "NavigationCurrentEntryChangeEvent", "NavigationDestination", "NavigationHistoryEntry", - "NavigationTransition" + "NavigationTransition", + "PageRevealEvent", + "PageSwapEvent" ], "methods": [], "properties": ["Window.navigation"], @@ -1702,12 +1705,7 @@ "View Transitions API": { "overview": ["View Transitions API"], "guides": ["/docs/Web/API/View_Transitions_API/Using"], - "interfaces": [ - "NavigationActivation", - "PageRevealEvent", - "PageSwapEvent", - "ViewTransition" - ], + "interfaces": ["ViewTransition"], "methods": ["Document.startViewTransition()"], "properties": [], "events": ["Window: pagereveal", "Window: pageswap"] From a03d960647a03cf178d8e418440664741dc4caa1 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 22 Mar 2024 15:53:22 +0000 Subject: [PATCH 08/53] Add docs for PageRevealEvent and PageSwapEvent --- files/en-us/web/api/pagerevealevent/index.md | 46 +++++++++++++ .../pagerevealevent/pagerevealevent/index.md | 45 +++++++++++++ .../pagerevealevent/viewtransition/index.md | 34 ++++++++++ .../web/api/pageswapevent/activation/index.md | 33 ++++++++++ files/en-us/web/api/pageswapevent/index.md | 66 +++++++++++++++++++ .../api/pageswapevent/pageswapevent/index.md | 47 +++++++++++++ .../api/pageswapevent/viewtransition/index.md | 33 ++++++++++ .../web/api/view_transitions_api/index.md | 4 +- files/jsondata/GroupData.json | 6 +- 9 files changed, 307 insertions(+), 7 deletions(-) create mode 100644 files/en-us/web/api/pagerevealevent/index.md create mode 100644 files/en-us/web/api/pagerevealevent/pagerevealevent/index.md create mode 100644 files/en-us/web/api/pagerevealevent/viewtransition/index.md create mode 100644 files/en-us/web/api/pageswapevent/activation/index.md create mode 100644 files/en-us/web/api/pageswapevent/index.md create mode 100644 files/en-us/web/api/pageswapevent/pageswapevent/index.md create mode 100644 files/en-us/web/api/pageswapevent/viewtransition/index.md diff --git a/files/en-us/web/api/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/index.md new file mode 100644 index 000000000000000..8c605dca9babcbf --- /dev/null +++ b/files/en-us/web/api/pagerevealevent/index.md @@ -0,0 +1,46 @@ +--- +title: PageRevealEvent +slug: Web/API/PageRevealEvent +page-type: web-api-interface +status: + - experimental +browser-compat: api.PageRevealEvent +--- + +{{APIRef("View Transitions API")}}{{SeeCompatTable}} + +The **`PageRevealEvent`** interface of the [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) is the event object for the {{domxref("Window.pagereveal_event", "pagereveal")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. + +## Constructor + +- {{domxref("PageRevealEvent.PageRevealEvent", "PageRevealEvent()")}} + - : Creates a new {{domxref("PageRevealEvent")}} object instance. + +## Instance properties + +- {{domxref("PageRevealEvent.viewTransition", "viewTransition")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : Contains a {{domxref("ViewTransition")}} object representing the active view transition for the cross-document navigation. + +## Examples + +```js +// This would run both on initial load and on reactivation from BFCache. +addEventListener("pagereveal", async (event) => { + // Skip the transition + event.viewTransition.skipTransition(); +}); +``` + +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/pagerevealevent/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/pagerevealevent/index.md new file mode 100644 index 000000000000000..8fe34478e9ef79d --- /dev/null +++ b/files/en-us/web/api/pagerevealevent/pagerevealevent/index.md @@ -0,0 +1,45 @@ +--- +title: "PageRevealEvent: PageRevealEvent() constructor" +short-title: PageRevealEvent() +slug: Web/API/PageRevealEvent/PageRevealEvent +page-type: web-api-constructor +status: + - experimental +browser-compat: api.PageRevealEvent.PageRevealEvent +--- + +{{APIRef("View Transitions API")}}{{SeeCompatTable}} + +The **`PageRevealEvent()`** constructor creates a new +{{domxref("PageRevealEvent")}} object instance. + +## Syntax + +```js-nolint +new PageRevealEvent(type, init) +``` + +### Parameters + +- `type` + - : A string representing the type of event. In the case of `PageRevealEvent` this is always `pagereveal`. +- `init` + - : An object containing the following properties: + - `viewTransition` {{optional_inline}} + - : A {{domxref("ViewTransition")}} object representing the active view transition for the related navigation. Defaults to `null` if there is no active view transition. + +## Examples + +A developer would not use this constructor manually. A new `PageRevealEvent` object is constructed when a handler is invoked as a result of the {{domxref("Window.pagereveal_event", "pagereveal")}} event firing. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/pagerevealevent/viewtransition/index.md b/files/en-us/web/api/pagerevealevent/viewtransition/index.md new file mode 100644 index 000000000000000..48d7254d4b81c2c --- /dev/null +++ b/files/en-us/web/api/pagerevealevent/viewtransition/index.md @@ -0,0 +1,34 @@ +--- +title: "PageRevealEvent: viewTransition property" +short-title: from +slug: Web/API/PageRevealEvent/viewTransition +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.PageRevealEvent.viewTransition +--- + +{{APIRef("View Transitions API")}}{{SeeCompatTable}} + +The **`viewTransition`** read-only property of the {{domxref("PageRevealEvent")}} interface contains a {{domxref("ViewTransition")}} object representing the active view transition for the cross-document navigation. + +## Value + +A {{domxref("ViewTransition")}} object, or `null` if no view transition is active when the event is fired. + +## Examples + +See the main {{domxref("PageRevealEvent")}} reference page for examples. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Navigation API](/en-US/docs/Web/API/Navigation_API) +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/pageswapevent/activation/index.md b/files/en-us/web/api/pageswapevent/activation/index.md new file mode 100644 index 000000000000000..a503d8bca5797b3 --- /dev/null +++ b/files/en-us/web/api/pageswapevent/activation/index.md @@ -0,0 +1,33 @@ +--- +title: "PageSwapEvent: activation property" +short-title: from +slug: Web/API/PageSwapEvent/activation +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.PageSwapEvent.viewTransition +--- + +{{APIRef("View Transitions API")}}{{SeeCompatTable}} + +The **`activation`** read-only property of the {{domxref("PageSwapEvent")}} interface contains a {{domxref("NavigationActivation")}} object representing the navigation type and current and destination document history entries. + +## Value + +A {{domxref("NavigationActivation")}} object, or `null` if the associated navigation is a cross-origin navigation. + +## Examples + +See the main {{domxref("PageSwapEvent")}} reference page for an example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md new file mode 100644 index 000000000000000..c1af3220dce111e --- /dev/null +++ b/files/en-us/web/api/pageswapevent/index.md @@ -0,0 +1,66 @@ +--- +title: PageSwapEvent +slug: Web/API/PageSwapEvent +page-type: web-api-interface +status: + - experimental +browser-compat: api.PageSwapEvent +--- + +{{APIRef("View Transitions API")}}{{SeeCompatTable}} + +The **`PageSwapEvent`** interface of the [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) is the event object for the {{domxref("Window.pageswap_event", "pageswap")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination documents. + +## Constructor + +- {{domxref("PageSwapEvent.PageSwapEvent", "PageSwapEvent()")}} + - : Creates a new {{domxref("PageSwapEvent")}} object instance. + +## Instance properties + +- {{domxref("PageSwapEvent.activation", "activation")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : Contains a {{domxref("NavigationActivation")}} object representing the navigation type and current and destination document history entries. +- {{domxref("PageSwapEvent.viewTransition", "viewTransition")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : Contains a {{domxref("ViewTransition")}} object representing the active view transition for the cross-document navigation. + +## Examples + +```js +window.addEventListener("pageswap", (event) => { + // Return if there is no active view transition + if (!event.viewTransition) { + return; + } + + // Grab the paths of the from and to URLs + const from_path = new URL(event.activation.from).pathname; + const to_path = new URL(event.activation.entry).pathname; + + // Skip transitions from landing to home + if (from_path === "/landing" && to_path === "/home") { + event.viewTransition.skipTransition(); + } + + // Apply a different style when going "back" + const is_back = + event.activation.navigationType === "traverse" && + event.activation.entry?.index === event.activation.from?.index - 1; + + // Add a class to the element for targetting a different back animation + // Note that this would only apply to capturing the final state of the old document, + // The new document would have to do this or something similar in `pagereveal`. + document.documentElement.classList.toggle("back-nav", is_back); +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/pageswapevent/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/pageswapevent/index.md new file mode 100644 index 000000000000000..aeedfc9d967e2ee --- /dev/null +++ b/files/en-us/web/api/pageswapevent/pageswapevent/index.md @@ -0,0 +1,47 @@ +--- +title: "PageSwapEvent: PageSwapEvent() constructor" +short-title: PageSwapEvent() +slug: Web/API/PageSwapEvent/PageSwapEvent +page-type: web-api-constructor +status: + - experimental +browser-compat: api.PageSwapEvent.PageSwapEvent +--- + +{{APIRef("View Transitions API")}}{{SeeCompatTable}} + +The **`PageSwapEvent()`** constructor creates a new +{{domxref("PageSwapEvent")}} object instance. + +## Syntax + +```js-nolint +new PageSwapEvent(type, init) +``` + +### Parameters + +- `type` + - : A string representing the type of event. In the case of `PageSwapEvent` this is always `pageswap`. +- `init` + - : An object containing the following properties: + - `activation` + - : A {{domxref("NavigationActivation")}} object representing the navigation type and current and destination document history entries. Defaults to `null` if the associated navigation is a cross-origin navigation. + - `viewTransition` + - : A {{domxref("ViewTransition")}} object representing the active view transition for the related navigation. Defaults to `null` if there is no active view transition. + +## Examples + +A developer would not use this constructor manually. A new `PageSwapEvent` object is constructed when a handler is invoked as a result of the {{domxref("Window.pageswap_event", "pageswap")}} event firing. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/pageswapevent/viewtransition/index.md b/files/en-us/web/api/pageswapevent/viewtransition/index.md new file mode 100644 index 000000000000000..1aaad283ed8e3b9 --- /dev/null +++ b/files/en-us/web/api/pageswapevent/viewtransition/index.md @@ -0,0 +1,33 @@ +--- +title: "PageSwapEvent: viewTransition property" +short-title: from +slug: Web/API/PageSwapEvent/viewTransition +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.PageSwapEvent.viewTransition +--- + +{{APIRef("View Transitions API")}}{{SeeCompatTable}} + +The **`viewTransition`** read-only property of the {{domxref("PageRevealEvent")}} interface contains a {{domxref("ViewTransition")}} object representing the active view transition for the cross-document navigation. + +## Value + +A {{domxref("ViewTransition")}} object, or `null` if no view transition is active when the event is fired. + +## Examples + +See the main {{domxref("PageSwapEvent")}} reference page for an example. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index a35423cd16b24d9..d6ab1fe5cd314fc 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -33,12 +33,10 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us ## Interfaces -- {{domxref("NavigationActivation")}} - - : Represents a recent cross-document navigation. It contains the navigation type and current and destination document history entries. - {{domxref("PageRevealEvent")}} - : The event object for the {{domxref("Window.pagereveal_event", "pagereveal")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. - {{domxref("PageSwapEvent")}} - - : The event object for the {{domxref("Window.pageswap_event", "pageswap")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination documents. + - : The event object for the {{domxref("Window.pageswap_event", "pageswap")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination document history entries. - {{domxref("ViewTransition")}} - : Represents a view transition, and provides functionality to react to the transition reaching different states (e.g. ready to run the animation, or animation finished) or skip the transition altogether. diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index d0d1721c4900d33..66ea71149c2172b 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -1015,9 +1015,7 @@ "NavigationCurrentEntryChangeEvent", "NavigationDestination", "NavigationHistoryEntry", - "NavigationTransition", - "PageRevealEvent", - "PageSwapEvent" + "NavigationTransition" ], "methods": [], "properties": ["Window.navigation"], @@ -1705,7 +1703,7 @@ "View Transitions API": { "overview": ["View Transitions API"], "guides": ["/docs/Web/API/View_Transitions_API/Using"], - "interfaces": ["ViewTransition"], + "interfaces": ["PageRevealEvent", "PageSwapEvent", "ViewTransition"], "methods": ["Document.startViewTransition()"], "properties": [], "events": ["Window: pagereveal", "Window: pageswap"] From 8b88c2acb21f183b1611f927d66ff25f96fee643 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Sat, 23 Mar 2024 14:24:18 +0000 Subject: [PATCH 09/53] fix folder naming issue --- .../{navigationType => navigationtype}/index.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename files/en-us/web/api/navigationactivation/{navigationType => navigationtype}/index.md (100%) diff --git a/files/en-us/web/api/navigationactivation/navigationType/index.md b/files/en-us/web/api/navigationactivation/navigationtype/index.md similarity index 100% rename from files/en-us/web/api/navigationactivation/navigationType/index.md rename to files/en-us/web/api/navigationactivation/navigationtype/index.md From dd176afa039f39d085862708b71e13cf4900ed2c Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Sun, 24 Mar 2024 12:34:34 +0000 Subject: [PATCH 10/53] Update files/en-us/web/api/viewtransition/index.md Co-authored-by: dawei-wang --- files/en-us/web/api/viewtransition/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/viewtransition/index.md b/files/en-us/web/api/viewtransition/index.md index 610af7dfa42855d..cf207c495b42c49 100644 --- a/files/en-us/web/api/viewtransition/index.md +++ b/files/en-us/web/api/viewtransition/index.md @@ -13,7 +13,7 @@ The **`ViewTransition`** interface of the {{domxref("View Transitions API", "Vie This object type is made available in the following ways: -- In the same of same-document (SPA) transitions, it is returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method. +- In the case of same-document (SPA) transitions, it is returned by the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method. - In the case of cross-document (MPA) transitions, it is made available: - In the outgoing page via the {{domxref("Window.pageswap_event", "pageswap")}} event object's {{domxref("PageSwapEvent.viewTransition")}} property. - In the inbound page via the {{domxref("Window.pagereveal_event", "pagereveal")}} event object's {{domxref("PageRevealEvent.viewTransition")}} property. From 175a58b7dd1300ffdbea9d2c2445e08429f40a59 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 26 Mar 2024 12:22:38 +0000 Subject: [PATCH 11/53] Improvements to demo links and explanations, make event objects part of HTML DOM --- .../api/navigationactivation/entry/index.md | 2 +- .../api/navigationactivation/from/index.md | 2 +- .../web/api/navigationactivation/index.md | 12 +- .../navigationtype/index.md | 12 +- files/en-us/web/api/pagerevealevent/index.md | 44 ++++- .../pagerevealevent/pagerevealevent/index.md | 2 +- .../pagerevealevent/viewtransition/index.md | 4 +- .../web/api/pageswapevent/activation/index.md | 8 +- files/en-us/web/api/pageswapevent/index.md | 77 +++++--- .../api/pageswapevent/pageswapevent/index.md | 2 +- .../api/pageswapevent/viewtransition/index.md | 4 +- .../web/api/view_transitions_api/index.md | 9 +- .../api/view_transitions_api/using/index.md | 173 ++++++++++++------ .../web/api/window/pagereveal_event/index.md | 38 +++- .../web/api/window/pageswap_event/index.md | 71 ++++--- files/jsondata/GroupData.json | 4 +- 16 files changed, 321 insertions(+), 143 deletions(-) diff --git a/files/en-us/web/api/navigationactivation/entry/index.md b/files/en-us/web/api/navigationactivation/entry/index.md index a3e70eb315798da..58bd91020640b54 100644 --- a/files/en-us/web/api/navigationactivation/entry/index.md +++ b/files/en-us/web/api/navigationactivation/entry/index.md @@ -20,7 +20,7 @@ A {{domxref("NavigationHistoryEntry")}} object. ## Examples -See the main {{domxref("NavigationActivation")}} reference page for an example. +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. ## Specifications diff --git a/files/en-us/web/api/navigationactivation/from/index.md b/files/en-us/web/api/navigationactivation/from/index.md index 34fd6182cb82c50..a855ba86914187d 100644 --- a/files/en-us/web/api/navigationactivation/from/index.md +++ b/files/en-us/web/api/navigationactivation/from/index.md @@ -21,7 +21,7 @@ A {{domxref("NavigationHistoryEntry")}} object, or `null` if the outgoing docume ## Examples -See the main {{domxref("NavigationActivation")}} reference page for an example. +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. ## Specifications diff --git a/files/en-us/web/api/navigationactivation/index.md b/files/en-us/web/api/navigationactivation/index.md index 886013a4c748064..c46c4bac9c0021f 100644 --- a/files/en-us/web/api/navigationactivation/index.md +++ b/files/en-us/web/api/navigationactivation/index.md @@ -39,19 +39,11 @@ window.addEventListener("pageswap", (event) => { if (from_path === "/landing" && to_path === "/home") { event.viewTransition.skipTransition(); } - - // Apply a different style when going "back" - const is_back = - event.activation.navigationType === "traverse" && - event.activation.entry?.index === event.activation.from?.index - 1; - - // Add a class to the element for targetting a different back animation - // Note that this would only apply to capturing the final state of the old document, - // The new document would have to do this or something similar in `pagereveal`. - document.documentElement.classList.toggle("back-nav", is_back); }); ``` +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example. + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/navigationactivation/navigationtype/index.md b/files/en-us/web/api/navigationactivation/navigationtype/index.md index 74ff34fc4bb07d0..c95e885f11e192c 100644 --- a/files/en-us/web/api/navigationactivation/navigationtype/index.md +++ b/files/en-us/web/api/navigationactivation/navigationtype/index.md @@ -23,7 +23,17 @@ A string representing the type of navigation the {{domxref("NavigationActivation ## Examples -See the main {{domxref("NavigationActivation")}} reference page for an example. +```js +window.addEventListener("pageswap", (event) => { + // For example, the page was hidden, or the navigation is cross-document. + if (!event.viewTransition) return; + + // Skip the view transition for back/forward navigations. + if (event.activation.navigationType === "traverse") { + event.viewTransition.skipTransition(); + } +}); +``` ## Specifications diff --git a/files/en-us/web/api/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/index.md index 8c605dca9babcbf..a8cd450e18e4e7c 100644 --- a/files/en-us/web/api/pagerevealevent/index.md +++ b/files/en-us/web/api/pagerevealevent/index.md @@ -7,9 +7,11 @@ status: browser-compat: api.PageRevealEvent --- -{{APIRef("View Transitions API")}}{{SeeCompatTable}} +{{APIRef("HTML DOM")}}{{SeeCompatTable}} -The **`PageRevealEvent`** interface of the [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) is the event object for the {{domxref("Window.pagereveal_event", "pagereveal")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. +The **`PageRevealEvent`** event object is made available inside handler functions for the {{domxref("Window.pagereveal_event", "pagereveal")}} event. + +During a cross-document navigation, it allows you to manipulate a related [view transition](/en-US/docs/Web/API/View_Transitions_API) (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. ## Constructor @@ -24,14 +26,42 @@ The **`PageRevealEvent`** interface of the [View Transitions API](/en-US/docs/We ## Examples ```js -// This would run both on initial load and on reactivation from BFCache. -addEventListener("pagereveal", async (event) => { - // Skip the transition - event.viewTransition.skipTransition(); +// When going from a detail page to the homepage, set `profile-name` and `profile-avatar` vt-names +// on the list item for the profile that was viewed on the detail page. +window.addEventListener("pagereveal", async (e) => { + if (!navigation.activation.from) return; + + if (e.viewTransition) { + const fromURL = new URL(navigation.activation.from.url); + const currentURL = new URL(navigation.activation.entry.url); + + // Only transition to/from same basePath + // ~> SKIP! + if (!fromURL.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } + + // Went from profile page to homepage + // ~> Set VT names on the relevant list item + if (profilePagePattern.test(fromURL) && homePagePattern.test(currentURL)) { + const match = profilePagePattern.exec(fromURL); + const profile = match?.pathname.groups.profile; + + document.querySelector(`#${profile} span`).style.viewTransitionName = + "profile-name"; + document.querySelector(`#${profile} img`).style.viewTransitionName = + "profile-avatar"; + + // Clean up after snapshots have been taken + await e.viewTransition.ready; + document.querySelector(`#${profile} span`).style.viewTransitionName = ""; + document.querySelector(`#${profile} img`).style.viewTransitionName = ""; + } + } }); ``` -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example. +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example with explanations. ## Specifications diff --git a/files/en-us/web/api/pagerevealevent/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/pagerevealevent/index.md index 8fe34478e9ef79d..3b87cbb0858abcc 100644 --- a/files/en-us/web/api/pagerevealevent/pagerevealevent/index.md +++ b/files/en-us/web/api/pagerevealevent/pagerevealevent/index.md @@ -8,7 +8,7 @@ status: browser-compat: api.PageRevealEvent.PageRevealEvent --- -{{APIRef("View Transitions API")}}{{SeeCompatTable}} +{{APIRef("HTML DOM")}}{{SeeCompatTable}} The **`PageRevealEvent()`** constructor creates a new {{domxref("PageRevealEvent")}} object instance. diff --git a/files/en-us/web/api/pagerevealevent/viewtransition/index.md b/files/en-us/web/api/pagerevealevent/viewtransition/index.md index 48d7254d4b81c2c..45f83727bd68657 100644 --- a/files/en-us/web/api/pagerevealevent/viewtransition/index.md +++ b/files/en-us/web/api/pagerevealevent/viewtransition/index.md @@ -8,7 +8,7 @@ status: browser-compat: api.PageRevealEvent.viewTransition --- -{{APIRef("View Transitions API")}}{{SeeCompatTable}} +{{APIRef("HTML DOM")}}{{SeeCompatTable}} The **`viewTransition`** read-only property of the {{domxref("PageRevealEvent")}} interface contains a {{domxref("ViewTransition")}} object representing the active view transition for the cross-document navigation. @@ -18,7 +18,7 @@ A {{domxref("ViewTransition")}} object, or `null` if no view transition is activ ## Examples -See the main {{domxref("PageRevealEvent")}} reference page for examples. +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. ## Specifications diff --git a/files/en-us/web/api/pageswapevent/activation/index.md b/files/en-us/web/api/pageswapevent/activation/index.md index a503d8bca5797b3..dcae7bf859b792f 100644 --- a/files/en-us/web/api/pageswapevent/activation/index.md +++ b/files/en-us/web/api/pageswapevent/activation/index.md @@ -8,17 +8,17 @@ status: browser-compat: api.PageSwapEvent.viewTransition --- -{{APIRef("View Transitions API")}}{{SeeCompatTable}} +{{APIRef("HTML DOM")}}{{SeeCompatTable}} -The **`activation`** read-only property of the {{domxref("PageSwapEvent")}} interface contains a {{domxref("NavigationActivation")}} object representing the navigation type and current and destination document history entries. +The **`activation`** read-only property of the {{domxref("PageSwapEvent")}} interface contains a {{domxref("NavigationActivation")}} object containing the navigation type and current and destination document history entries for a same-origin navigation. ## Value -A {{domxref("NavigationActivation")}} object, or `null` if the associated navigation is a cross-origin navigation. +A {{domxref("NavigationActivation")}} object, or `null` if the associated navigation has a cross-origin URL anywhere in the redirect chain. ## Examples -See the main {{domxref("PageSwapEvent")}} reference page for an example. +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. ## Specifications diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index c1af3220dce111e..79603e86ebc28ab 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -7,9 +7,11 @@ status: browser-compat: api.PageSwapEvent --- -{{APIRef("View Transitions API")}}{{SeeCompatTable}} +{{APIRef("HTML DOM")}}{{SeeCompatTable}} -The **`PageSwapEvent`** interface of the [View Transitions API](/en-US/docs/Web/API/View_Transitions_API) is the event object for the {{domxref("Window.pageswap_event", "pageswap")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination documents. +The **`PageSwapEvent`** event object is made available inside handler functions for the {{domxref("Window.pageswap_event", "pageswap")}} event. + +During a cross-document navigation, it allows you to manipulate the related [view transition](/en-US/docs/Web/API/View_Transitions_API) (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination documents. ## Constructor @@ -19,40 +21,63 @@ The **`PageSwapEvent`** interface of the [View Transitions API](/en-US/docs/Web/ ## Instance properties - {{domxref("PageSwapEvent.activation", "activation")}} {{ReadOnlyInline}} {{Experimental_Inline}} - - : Contains a {{domxref("NavigationActivation")}} object representing the navigation type and current and destination document history entries. + - : Contains a {{domxref("NavigationActivation")}} object containing the navigation type and current and destination document history entries for a same-origin navigation. If the navigation has a cross-origin URL anywhere in the redirect chain, it returns `null`. - {{domxref("PageSwapEvent.viewTransition", "viewTransition")}} {{ReadOnlyInline}} {{Experimental_Inline}} - : Contains a {{domxref("ViewTransition")}} object representing the active view transition for the cross-document navigation. ## Examples ```js -window.addEventListener("pageswap", (event) => { - // Return if there is no active view transition - if (!event.viewTransition) { - return; - } - - // Grab the paths of the from and to URLs - const from_path = new URL(event.activation.from).pathname; - const to_path = new URL(event.activation.entry).pathname; - - // Skip transitions from landing to home - if (from_path === "/landing" && to_path === "/home") { - event.viewTransition.skipTransition(); +// When going to a detail page, set `profile-name` and `profile-avatar` vt-names +// on the elements that link to that detail page +window.addEventListener("pageswap", async (e) => { + if (e.viewTransition) { + const url = new URL(e.activation.entry.url); + + // Only transition to same basePath + // ~> SKIP! + if (!url.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } + + // Extract name from URL + const match = profilePagePattern.exec(url); + const profile = match?.pathname.groups.profile; + + // No name extract = not going to a detail page + // ~> Don’t tweak VT + if (!profile) return; + + // Set VT-names on clicked name + document.querySelector(`#${profile} span`).style.viewTransitionName = + "profile-name"; + document.querySelector(`#${profile} img`).style.viewTransitionName = + "profile-avatar"; + + // Remove VT-names from currently shown ones when already at a detail page + // @TODO: Figure out why I had to set to x and y here, instead of just '' + if (profilePagePattern.test(window.location.href)) { + document.querySelector(`main h1`).style.viewTransitionName = "x"; + document.querySelector(`main img`).style.viewTransitionName = "y"; + } + + // Restore orig VT names after snapshots have been taken + // (This to deal with BFCache) + await e.viewTransition.finished; + document.querySelector(`#${profile} span`).style.viewTransitionName = "z"; + document.querySelector(`#${profile} img`).style.viewTransitionName = "w"; + if (profilePagePattern.test(window.location.href)) { + document.querySelector(`main h1`).style.viewTransitionName = + "profile-name"; + document.querySelector(`main img`).style.viewTransitionName = + "profile-avatar"; + } } - - // Apply a different style when going "back" - const is_back = - event.activation.navigationType === "traverse" && - event.activation.entry?.index === event.activation.from?.index - 1; - - // Add a class to the element for targetting a different back animation - // Note that this would only apply to capturing the final state of the old document, - // The new document would have to do this or something similar in `pagereveal`. - document.documentElement.classList.toggle("back-nav", is_back); }); ``` +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example with explanations. + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/pageswapevent/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/pageswapevent/index.md index aeedfc9d967e2ee..e5336b3a418f2cf 100644 --- a/files/en-us/web/api/pageswapevent/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/pageswapevent/index.md @@ -8,7 +8,7 @@ status: browser-compat: api.PageSwapEvent.PageSwapEvent --- -{{APIRef("View Transitions API")}}{{SeeCompatTable}} +{{APIRef("HTML DOM")}}{{SeeCompatTable}} The **`PageSwapEvent()`** constructor creates a new {{domxref("PageSwapEvent")}} object instance. diff --git a/files/en-us/web/api/pageswapevent/viewtransition/index.md b/files/en-us/web/api/pageswapevent/viewtransition/index.md index 1aaad283ed8e3b9..598355d8ed52a42 100644 --- a/files/en-us/web/api/pageswapevent/viewtransition/index.md +++ b/files/en-us/web/api/pageswapevent/viewtransition/index.md @@ -8,7 +8,7 @@ status: browser-compat: api.PageSwapEvent.viewTransition --- -{{APIRef("View Transitions API")}}{{SeeCompatTable}} +{{APIRef("HTML DOM")}}{{SeeCompatTable}} The **`viewTransition`** read-only property of the {{domxref("PageRevealEvent")}} interface contains a {{domxref("ViewTransition")}} object representing the active view transition for the cross-document navigation. @@ -18,7 +18,7 @@ A {{domxref("ViewTransition")}} object, or `null` if no view transition is activ ## Examples -See the main {{domxref("PageSwapEvent")}} reference page for an example. +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. ## Specifications diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index d6ab1fe5cd314fc..a54bfcaf8a1f437 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -33,10 +33,6 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us ## Interfaces -- {{domxref("PageRevealEvent")}} - - : The event object for the {{domxref("Window.pagereveal_event", "pagereveal")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. -- {{domxref("PageSwapEvent")}} - - : The event object for the {{domxref("Window.pageswap_event", "pageswap")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination document history entries. - {{domxref("ViewTransition")}} - : Represents a view transition, and provides functionality to react to the transition reaching different states (e.g. ready to run the animation, or animation finished) or skip the transition altogether. @@ -44,6 +40,10 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us - {{domxref("Document.startViewTransition()")}} - : Starts a new same-document (SPA) view transition and returns a {{domxref("ViewTransition")}} object to represent it. +- {{domxref("PageRevealEvent")}} + - : The event object for the {{domxref("Window.pagereveal_event", "pagereveal")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. +- {{domxref("PageSwapEvent")}} + - : The event object for the {{domxref("Window.pageswap_event", "pageswap")}} event. During a cross-document navigation, it allows you to manipulate the related view transition (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination document history entries. - The {{domxref("Window")}} {{domxref("Window.pagereveal_event", "pagereveal")}} event - : Fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](https://web.dev/articles/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). - The {{domxref("Window")}} {{domxref("Window.pageswap_event", "pageswap")}} event @@ -84,6 +84,7 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us - [Basic View Transitions SPA demo](https://mdn.github.io/dom-examples/view-transitions/spa/): A basic image gallery demo with view transitions, featuring separate animations between old and new images, and old and new captions. - [Basic View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transitions/mpa/): A sample two-page site that demonstrates usage of cross-document (MPA) view transitions, providing a custom "swipe up" transition when the two pages are navigated between. - [HTTP 203 playlist](https://http203-playlist.netlify.app/): A video player demo app that features several different SPA view transitions, many of which are explained in [Smooth and simple transitions with the View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions/). +- [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/): A basic team profile pages app that demonstrates how to use the {{domxref("Window.pagereveal_event", "pagereveal")}} and {{domxref("Window.pageswap_event", "pageswap")}} events to customize the outgoing and inbound animations of a cross-document view transition based on the "from" and "to" URLs. ## Specifications diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index b00508f0bfb3532..6c1a296bd1a83b0 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -258,7 +258,8 @@ The `ViewTransition` can be accessed like so: 1. In the case of same-document (SPA) transitions, the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method returns the `ViewTransition` associated with the transition. 2. In the case of cross-document (MPA) transitions: -- A {{domxref("Window.pageswap_event", "pageswap")}} event is fired when a document is about to be unloaded due to a navigation. Its event object ({{domxref("PageSwapEvent")}}) provides access to the `ViewTransition` via the {{domxref("PageSwapEvent.viewTransition")}} property, as well as a {{domxref("NavigationActivation")}} containing the navigation type and current and destination document history entries. +- A {{domxref("Window.pageswap_event", "pageswap")}} event is fired when a document is about to be unloaded due to a navigation. Its event object ({{domxref("PageSwapEvent")}}) provides access to the `ViewTransition` via the {{domxref("PageSwapEvent.viewTransition")}} property, as well as a {{domxref("NavigationActivation")}} via {{domxref("PageSwapEvent.activation")}} containing the navigation type and current and destination document history entries. + > **Note:** If the navigation has a cross-origin URL anywhere in the redirect chain, the `activation` property returns `null`. - A {{domxref("Window.pagereveal_event", "pagereveal")}} event is fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](https://web.dev/articles/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). Its event object ({{domxref("PageRevealEvent")}}) provides access to the `ViewTransition` via the {{domxref("PageRevealEvent.viewTransition")}} property. Let's have a look at some example code to show how these features could be used. @@ -331,58 +332,124 @@ This animation also requires the following CSS, to turn off the default CSS anim ### A JavaScript-powered custom cross-document (MPA) transition -To achieve the same circular reveal view transition during a cross-document navigation, multiple steps are required: - -1. Opt both pages in to cross-document view transitions using the {{cssxref("@view-transition")}} at rule, the same as we saw earlier: - - ```css - @view-transition { - navigation: auto; - } - ``` - -2. Store the mouse click location on the current page in [web storage](/en-US/docs/Web/API/Web_Storage_API) so that it can be retrieved by the destination page: - - ```js - addEventListener("click", (event) => { - sessionStorage.setItem("lastClickX", event.clientX); - sessionStorage.setItem("lastClickY", event.clientY); - }); - ``` - -3. Intercept the `ViewTransition` in the new document via the `pagereveal` event and use it to create the custom animation: - - ```js - // This would run both on initial load and on reactivation from BFCache. - addEventListener("pagereveal", async (event) => { - if (!event.viewTransition) return; - - const x = sessionStorage.getItem("lastClickX") ?? innerWidth / 2; - const y = sessionStorage.getItem("lastClickY") ?? innerHeight / 2; - - const endRadius = Math.hypot( - Math.max(x, innerWidth - x), - Math.max(y, innerHeight - y), - ); - - await event.viewTransition.ready; - - // Animate the new document's 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", - pseudoElement: "::view-transition-new(root)", - }, - ); - }); - ``` +The [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) demo provides a basic set of team profile pages, and demonstrates how to use the {{domxref("Window.pagereveal_event", "pagereveal")}} and {{domxref("Window.pageswap_event", "pageswap")}} events to customize the outgoing and inbound animations of a cross-document view transition based on the "from" and "to" URLs. + +The JavaScript starts like this, defining the homepage path and creating {{domxref("URLPattern")}}s to represent the homepage and profile pages: + +```js +// Path where this app is deployed. Because we don’t deploy at the root of the domain +// we need to keep track of this and adjust any URL matching using this value. +const basePath = "/profiles/mpa"; + +const homePagePattern = new URLPattern(`${basePath}/`, window.origin); +const profilePagePattern = new URLPattern( + `${basePath}/:profile`, + window.origin, +); +``` + +The {{domxref("Window.pageswap_event", "pageswap")}} event listener looks as follows. This sets view transition names on the elements on the outbound page that link to the profile pages. When navigating from the home page to a profile page, custom animations are provided _only_ for the linked element that is clicked in each case. + +In this block we: + +- Grab the URL of the inbound document in the navigation from the {{domxref("NavigationHistoryEntry")}} object available at {{domxref("NavigationActivation.entry", "PageSwapEvent.activation.entry")}}. +- Skip the transition if the inbound document's URL does not start with the same `basePath` as the current document. This is done using the {{domxref("ViewTransition.skipTransition()", "skipTransition()")}} method of the {{domxref("ViewTransition")}} object available at {{domxref("PageSwapEvent.viewTransition")}}. +- Extract the profile name from the inbound URL using the `profilePagePattern`. +- Return out of the event listener if there is no profile name, i.e. the link is not navigating to a profile page. In this case, we don't want to customize the view transitions. +- Set view transition names on the relevant profile name and avatar so that they are animated during the navigation, and remove previously set view transition names to tidy up and ensure that the wrong elements do not animate. + +```js +// When going to a detail page, set `profile-name` and `profile-avatar` vt-names +// on the elements that link to that detail page +window.addEventListener("pageswap", async (e) => { + if (e.viewTransition) { + const url = new URL(e.activation.entry.url); + + // Only transition to same basePath + // ~> SKIP! + if (!url.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } + + // Extract name from URL + const match = profilePagePattern.exec(url); + const profile = match?.pathname.groups.profile; + + // No name extract = not going to a detail page + // ~> Don’t tweak VT + if (!profile) return; + + // Set VT-names on clicked name + document.querySelector(`#${profile} span`).style.viewTransitionName = + "profile-name"; + document.querySelector(`#${profile} img`).style.viewTransitionName = + "profile-avatar"; + + // Remove VT-names from currently shown ones when already at a detail page + // @TODO: Figure out why I had to set to x and y here, instead of just '' + if (profilePagePattern.test(window.location.href)) { + document.querySelector(`main h1`).style.viewTransitionName = "x"; + document.querySelector(`main img`).style.viewTransitionName = "y"; + } + + // Restore orig VT names after snapshots have been taken + // (This to deal with BFCache) + await e.viewTransition.finished; + document.querySelector(`#${profile} span`).style.viewTransitionName = "z"; + document.querySelector(`#${profile} img`).style.viewTransitionName = "w"; + if (profilePagePattern.test(window.location.href)) { + document.querySelector(`main h1`).style.viewTransitionName = + "profile-name"; + document.querySelector(`main img`).style.viewTransitionName = + "profile-avatar"; + } + } +}); +``` + +The {{domxref("Window.pagereveal_event", "pagereveal")}} event listener looks as follows. This works in a similar way to the `pageswap` event listener, although bear in mind that here we are customizing to "to" animation, for page elements on the inbound page. In this case, we: + +- Return out of the event listener if there is no {{domxref("NavigationActivation.from", "PageSwapEvent.activation.from")}} history entry. We don't want an animation if we are going straight to the page and not navigation from somewhere else. +- grab the "from" and "to" (current) URLs from the {{domxref("NavigationHistoryEntry")}} objects available at {{domxref("NavigationActivation.from", "PageRevealEvent.activation.from")}} and {{domxref("NavigationActivation.entry", "PageRevealEvent.activation.entry")}}. +- Skip the transition if the inbound document's URL does not start with the same `basePath` as the current document. This is done using the {{domxref("ViewTransition.skipTransition()", "skipTransition()")}} method of the {{domxref("ViewTransition")}} object available at {{domxref("PageSwapEvent.viewTransition")}}. +- Test the "from" and "to" (current) URLs using the `profilePagePattern` and `homePagePattern`, only running the next step if the "from" page is a profile page and the "to" page is the homepage. +- Set view transition names on the relevant list item features so that they are animated during the navigation, and remove previously set view transition names to tidy up and ensure that the wrong elements do not animate. + +```js +// When going from a detail page to the homepage, set `profile-name` and `profile-avatar` vt-names +// on the list item for the profile that was viewed on the detail page. +window.addEventListener("pagereveal", async (e) => { + if (!navigation.activation.from) return; + + if (e.viewTransition) { + const fromURL = new URL(navigation.activation.from.url); + const currentURL = new URL(navigation.activation.entry.url); + + // Only transition to/from same basePath + // ~> SKIP! + if (!fromURL.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } + + // Went from profile page to homepage + // ~> Set VT names on the relevant list item + if (profilePagePattern.test(fromURL) && homePagePattern.test(currentURL)) { + const match = profilePagePattern.exec(fromURL); + const profile = match?.pathname.groups.profile; + + document.querySelector(`#${profile} span`).style.viewTransitionName = + "profile-name"; + document.querySelector(`#${profile} img`).style.viewTransitionName = + "profile-avatar"; + + // Clean up after snapshots have been taken + await e.viewTransition.ready; + document.querySelector(`#${profile} span`).style.viewTransitionName = ""; + document.querySelector(`#${profile} img`).style.viewTransitionName = ""; + } + } +}); +``` ## Making cross-document transitions consistent with `rel="expect"` diff --git a/files/en-us/web/api/window/pagereveal_event/index.md b/files/en-us/web/api/window/pagereveal_event/index.md index 323d7e14649ef10..af075c6a7385736 100644 --- a/files/en-us/web/api/window/pagereveal_event/index.md +++ b/files/en-us/web/api/window/pagereveal_event/index.md @@ -37,14 +37,42 @@ A {{domxref("PageRevealEvent")}}. Inherits from {{domxref("Event")}}. ## Examples ```js -// This would run both on initial load and on reactivation from BFCache. -addEventListener("pagereveal", async (event) => { - // Skip the transition - event.viewTransition.skipTransition(); +// When going from a detail page to the homepage, set `profile-name` and `profile-avatar` vt-names +// on the list item for the profile that was viewed on the detail page. +window.addEventListener("pagereveal", async (e) => { + if (!navigation.activation.from) return; + + if (e.viewTransition) { + const fromURL = new URL(navigation.activation.from.url); + const currentURL = new URL(navigation.activation.entry.url); + + // Only transition to/from same basePath + // ~> SKIP! + if (!fromURL.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } + + // Went from profile page to homepage + // ~> Set VT names on the relevant list item + if (profilePagePattern.test(fromURL) && homePagePattern.test(currentURL)) { + const match = profilePagePattern.exec(fromURL); + const profile = match?.pathname.groups.profile; + + document.querySelector(`#${profile} span`).style.viewTransitionName = + "profile-name"; + document.querySelector(`#${profile} img`).style.viewTransitionName = + "profile-avatar"; + + // Clean up after snapshots have been taken + await e.viewTransition.ready; + document.querySelector(`#${profile} span`).style.viewTransitionName = ""; + document.querySelector(`#${profile} img`).style.viewTransitionName = ""; + } + } }); ``` -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example. +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example with explanations. ## Specifications diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index 4541e11c071375b..bf7d8256a1fd2d5 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -34,40 +34,63 @@ A {{domxref("PageSwapEvent")}}. Inherits from {{domxref("Event")}}. ## Event properties - {{domxref("PageSwapEvent.activation")}} {{ReadOnlyInline}} - - : Returns a {{domxref("NavigationActivation")}} object containing the navigation type and current and destination document history entries for a same-origin navigation. If the navigation is cross-origin, it returns `null`. + - : Returns a {{domxref("NavigationActivation")}} object containing the navigation type and current and destination document history entries for a same-origin navigation. If the navigation has a cross-origin URL anywhere in the redirect chain, it returns `null`. - {{domxref("PageSwapEvent.viewTransition")}} {{ReadOnlyInline}} - : Returns the {{domxref("ViewTransition")}} object representing the inbound cross-document view transition, if one is active when the event is fired. If this is not the case, it returns `null`. ## Examples ```js -window.addEventListener("pageswap", (event) => { - // Return if there is no active view transition - if (!event.viewTransition) { - return; +// When going to a detail page, set `profile-name` and `profile-avatar` vt-names +// on the elements that link to that detail page +window.addEventListener("pageswap", async (e) => { + if (e.viewTransition) { + const url = new URL(e.activation.entry.url); + + // Only transition to same basePath + // ~> SKIP! + if (!url.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } + + // Extract name from URL + const match = profilePagePattern.exec(url); + const profile = match?.pathname.groups.profile; + + // No name extract = not going to a detail page + // ~> Don’t tweak VT + if (!profile) return; + + // Set VT-names on clicked name + document.querySelector(`#${profile} span`).style.viewTransitionName = + "profile-name"; + document.querySelector(`#${profile} img`).style.viewTransitionName = + "profile-avatar"; + + // Remove VT-names from currently shown ones when already at a detail page + // @TODO: Figure out why I had to set to x and y here, instead of just '' + if (profilePagePattern.test(window.location.href)) { + document.querySelector(`main h1`).style.viewTransitionName = "x"; + document.querySelector(`main img`).style.viewTransitionName = "y"; + } + + // Restore orig VT names after snapshots have been taken + // (This to deal with BFCache) + await e.viewTransition.finished; + document.querySelector(`#${profile} span`).style.viewTransitionName = "z"; + document.querySelector(`#${profile} img`).style.viewTransitionName = "w"; + if (profilePagePattern.test(window.location.href)) { + document.querySelector(`main h1`).style.viewTransitionName = + "profile-name"; + document.querySelector(`main img`).style.viewTransitionName = + "profile-avatar"; + } } - - // Grab the paths of the from and to URLs - const from_path = new URL(event.activation.from).pathname; - const to_path = new URL(event.activation.entry).pathname; - - // Skip transitions from landing to home - if (from_path === "/landing" && to_path === "/home") { - event.viewTransition.skipTransition(); - } - - // Apply a different style when going "back" - const is_back = - event.activation.navigationType === "traverse" && - event.activation.entry?.index === event.activation.from?.index - 1; - - // Add a class to the element for targetting a different back animation - // Note that this would only apply to capturing the final state of the old document, - // The new document would have to do this or something similar in `pagereveal`. - document.documentElement.classList.toggle("back-nav", is_back); }); ``` +> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example with explanations. + ## Specifications {{Specifications}} diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index b3fef95ad0645d6..0724bca2b89c32e 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -742,6 +742,8 @@ "MessageEvent", "MessagePort", "Navigator", + "PageRevealEvent", + "PageSwapEvent", "PageTransitionEvent", "Plugin", "PluginArray", @@ -1703,7 +1705,7 @@ "View Transitions API": { "overview": ["View Transitions API"], "guides": ["/docs/Web/API/View_Transitions_API/Using"], - "interfaces": ["PageRevealEvent", "PageSwapEvent", "ViewTransition"], + "interfaces": ["ViewTransition"], "methods": ["Document.startViewTransition()"], "properties": [], "events": ["Window: pagereveal", "Window: pageswap"] From a55a815268de3d482b0c7ed02b014e788c13c35d Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 26 Mar 2024 12:31:21 +0000 Subject: [PATCH 12/53] add PageRevealEvent and PageSwapEvent to HTML DOM landing page --- files/en-us/web/api/html_dom_api/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/en-us/web/api/html_dom_api/index.md b/files/en-us/web/api/html_dom_api/index.md index 922717a9242238d..a64cd5ec025bf7f 100644 --- a/files/en-us/web/api/html_dom_api/index.md +++ b/files/en-us/web/api/html_dom_api/index.md @@ -235,6 +235,8 @@ The History API interfaces let you access information about the browser's histor - {{DOMxRef("HashChangeEvent")}} - {{DOMxRef("History")}} - {{DOMxRef("Location")}} +- {{DOMxRef("PageRevealEvent")}} +- {{DOMxRef("PageSwapEvent")}} - {{DOMxRef("PageTransitionEvent")}} - {{DOMxRef("PopStateEvent")}} From 290489c979548b217bfeaf1c68f3176c24f904bb Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 12 Apr 2024 19:07:50 +0100 Subject: [PATCH 13/53] Fixes for bramus and noamr review comments --- .../api/document/startviewtransition/index.md | 2 +- .../navigationtype/index.md | 4 +- files/en-us/web/api/pagerevealevent/index.md | 6 -- files/en-us/web/api/pageswapevent/index.md | 8 +- .../web/api/view_transitions_api/index.md | 2 +- .../api/view_transitions_api/using/index.md | 99 ++++++++++++------- .../viewtransition/skiptransition/index.md | 3 - .../web/api/window/pageswap_event/index.md | 2 +- files/en-us/web/css/@view-transition/index.md | 4 +- .../index.md | 2 +- .../index.md | 3 +- .../_doublecolon_view-transition-new/index.md | 33 ++++--- .../_doublecolon_view-transition-old/index.md | 33 ++++--- .../css/_doublecolon_view-transition/index.md | 2 +- .../web/css/view-transition-name/index.md | 1 + files/en-us/web/html/attributes/rel/index.md | 20 +--- 16 files changed, 125 insertions(+), 99 deletions(-) diff --git a/files/en-us/web/api/document/startviewtransition/index.md b/files/en-us/web/api/document/startviewtransition/index.md index 48651a44c675c17..49d4f43b8b161d7 100644 --- a/files/en-us/web/api/document/startviewtransition/index.md +++ b/files/en-us/web/api/document/startviewtransition/index.md @@ -24,7 +24,7 @@ startViewTransition(updateCallback) ### Parameters - `updateCallback` {{optional_inline}} - - : An optional callback function typically invoked to update the DOM during the SPA view transition process, which returns a {{jsxref("Promise")}}. The callback is invoked once the API has taken a screenshot of the current page. When the promise returned by the callback fulfills, the view transition begins in the next frame. If the promise returned by the callback rejects, the transition is abandoned. + - : An optional callback function typically invoked to update the DOM during the SPA view transition process, which returns a {{jsxref("Promise")}}. The callback is invoked once the API has taken a snapshot of the current page. When the promise returned by the callback fulfills, the view transition begins in the next frame. If the promise returned by the callback rejects, the transition is abandoned. ### Return value diff --git a/files/en-us/web/api/navigationactivation/navigationtype/index.md b/files/en-us/web/api/navigationactivation/navigationtype/index.md index c95e885f11e192c..98743993dda7743 100644 --- a/files/en-us/web/api/navigationactivation/navigationtype/index.md +++ b/files/en-us/web/api/navigationactivation/navigationtype/index.md @@ -17,8 +17,8 @@ The **`navigationType`** read-only property of the {{domxref("NavigationActivati A string representing the type of navigation the {{domxref("NavigationActivation")}} relates to. Possible values are: - `push`: A new location was navigated to, causing a new entry to be pushed onto the history list. -- `reload`: The {{domxref("Navigation.currentEntry")}} was reloaded. -- `replace`: The {{domxref("Navigation.currentEntry")}} was replaced with a new history entry. This new entry will reuse the same {{domxref("NavigationHistoryEntry.key", "key")}}, but be assigned a different {{domxref("NavigationHistoryEntry.id", "id")}}. +- `reload`: The {{domxref("NavigationActivation.entry")}} was reloaded. +- `replace`: The {{domxref("NavigationActivation.entry")}} was replaced with a new history entry. This new entry will reuse the same {{domxref("NavigationHistoryEntry.key", "key")}}, but be assigned a different {{domxref("NavigationHistoryEntry.id", "id")}}. - `traverse`: The browser navigated from one existing history entry to another existing history entry. ## Examples diff --git a/files/en-us/web/api/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/index.md index a8cd450e18e4e7c..b02beb9983d3f73 100644 --- a/files/en-us/web/api/pagerevealevent/index.md +++ b/files/en-us/web/api/pagerevealevent/index.md @@ -35,12 +35,6 @@ window.addEventListener("pagereveal", async (e) => { const fromURL = new URL(navigation.activation.from.url); const currentURL = new URL(navigation.activation.entry.url); - // Only transition to/from same basePath - // ~> SKIP! - if (!fromURL.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Went from profile page to homepage // ~> Set VT names on the relevant list item if (profilePagePattern.test(fromURL) && homePagePattern.test(currentURL)) { diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index 79603e86ebc28ab..a1f3c6ca0a54b7b 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -11,7 +11,7 @@ browser-compat: api.PageSwapEvent The **`PageSwapEvent`** event object is made available inside handler functions for the {{domxref("Window.pageswap_event", "pageswap")}} event. -During a cross-document navigation, it allows you to manipulate the related [view transition](/en-US/docs/Web/API/View_Transitions_API) (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination documents. +The pageswap event is fired when you navigate across documents, when the previous document is about to unload. During a cross-document navigation, the `PageSwapEvent`\*\* event object allows you to manipulate the related [view transition](/en-US/docs/Web/API/View_Transitions_API) (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _from_, if a view transition was triggered by the navigation. It also provides access to information on the navigation type and current and destination documents. ## Constructor @@ -34,12 +34,6 @@ window.addEventListener("pageswap", async (e) => { if (e.viewTransition) { const url = new URL(e.activation.entry.url); - // Only transition to same basePath - // ~> SKIP! - if (!url.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Extract name from URL const match = profilePagePattern.exec(url); const profile = match?.pathname.groups.profile; diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index b5e1a0b60d6853b..aa804b83ab7174d 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -78,7 +78,7 @@ See [Using the View Transitions API](/en-US/docs/Web/API/View_Transitions_API/Us - {{cssxref("::view-transition-image-pair", "::view-transition-image-pair()")}} - : The container for a view transition's old and new views — before and after the transition. - {{cssxref("::view-transition-old", "::view-transition-old()")}} - - : A static screenshot of the old view, before the transition. + - : A static snapshot of the old view, before the transition. - {{cssxref("::view-transition-new", "::view-transition-new()")}} - : A live representation of the new view, after the transition. diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 6c1a296bd1a83b0..200dc040a358004 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -16,9 +16,9 @@ Let's walk through the process by which a view transition works: 1. A view transition is triggered. How this is done depends on the type of view transition: - In the case of same-document transitions (SPAs), a view transition is triggered by passing the function that would trigger the view change DOM update as a callback to the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} method. - - In the case of cross-document transitions (MPAs), a view transition is triggered by initiating navigation to a new document. Both the current and destination documents of the navigation need to opt-in to the view transition by including a {{cssxref("@view-transition")}} at rule in their CSS with a `navigation` descriptor of `auto`. - > **Note:** An active view transition has an associated {{domxref("ViewTransition")}} instance (for example, returned by `startViewTransition()` in the case of same-document (SPA) transitions). The `ViewTransition` object includes several promises, allowing you to run code in response to different parts of the view transition process being reached. See [Controlling view transitions with JavaScript](#controlling_view_transitions_with_javascript) for mroe information. -2. The API takes a screenshot of the current (old page) view. + - In the case of cross-document transitions (MPAs), a view transition is triggered by initiating navigation to a new document. Both the current and destination documents of the navigation need to be on the same origin, and opt-in to the view transition by including a {{cssxref("@view-transition")}} at rule in their CSS with a `navigation` descriptor of `auto`. + > **Note:** An active view transition has an associated {{domxref("ViewTransition")}} instance (for example, returned by `startViewTransition()` in the case of same-document (SPA) transitions). The `ViewTransition` object includes several promises, allowing you to run code in response to different parts of the view transition process being reached. See [Controlling view transitions with JavaScript](#controlling_view_transitions_with_javascript) for more information. +2. On the current (old page) view, the API captures snapshots of elements that have a {{cssxref("view-transition-name")}} declared on them. 3. The view change occurs: - In the case of same-document transitions (SPAs), the callback passed to `startViewTransition()` is invoked, which causes the DOM to change. @@ -27,12 +27,12 @@ Let's walk through the process by which a view transition works: - In the case of cross-document transitions (MPAs), the navigation occurs between the current and destination documents. -4. The API captures the new view as a live representation. +4. The API captures snapshots from the new view as a live representation. At this point, the view transition is about to run, and the {{domxref("ViewTransition.ready")}} promise fulfills, allowing you to respond by running a custom JavaScript animation instead of the default, for example. -5. The old page view animates "out", while the new view animates "in". By default, the old view animates from {{cssxref("opacity")}} 1 to 0 and the new view animates from `opacity` 0 to 1, which creates a cross-fade. -6. When the transition animation has reached its end state, the {{domxref("ViewTransition.finished")}} promise fulfills, allowing you to respond. +5. The old page snapshots animate "out", while the new view snapshots animate "in". By default, the old view snapshots animate from {{cssxref("opacity")}} 1 to 0, and the new view snapshots animate from `opacity` 0 to 1, which creates a cross-fade. +6. When the transition animations have reached their end states, the {{domxref("ViewTransition.finished")}} promise fulfills, allowing you to respond. ### The view transition pseudo-element tree @@ -46,13 +46,16 @@ To handle creating the outbound and inbound transition animations, the API const └─ ::view-transition-new(root) ``` -In the case of same-document transitions (SPAs), the pseudo-element tree is made available in the document. In the case of cross-document transitions (MPAs), the pseudo-element tree is made available in both the current and destination documents. +> **Note:** a {{cssxref("::view-transition-group")}} is created for every view-transition-name that was captured? + +In the case of same-document transitions (SPAs), the pseudo-element tree is made available in the document. In the case of cross-document transitions (MPAs), the pseudo-element tree is made available in the destination document only. The most interesting parts of the tree structure are as follows: -- {{cssxref("::view-transition")}} is the root of view transitions overlay, which contains all view transitions and sits over the top of all other page content. -- {{cssxref("::view-transition-old")}} targets the screenshot of the old page view, and {{cssxref("::view-transition-new")}} targets the live representation of the new page view. Both of these render as replaced content, in the same manner as an {{htmlelement("img")}} or {{htmlelement("video")}}, meaning that they can be styled with handy properties like {{cssxref("object-fit")}} and {{cssxref("object-position")}}. -- The `root` argument specifies the default grouping for the view transition — that the view transition animation will apply to all DOM elements that change when the view is updated. It is possible to use target different DOM elements with different custom view transition animations — see [Different transitions for different elements](#different_transitions_for_different_elements). +- {{cssxref("::view-transition")}} is the root of view transitions overlay, which contains all view transition snapshot groups and sits over the top of all other page content. +- A {{cssxref("::view-transition-group")}} acts as a container for each view transition snapshot group. The `root` argument specifies the default snapshot group — the view transition animation will apply to the `:root` element and all elements nested within it. + > **Note:** It is possible to target different DOM elements with different custom view transition animations by setting a different {{cssxref("view-transition-name")}} on each one. In such cases, a `::view-transition-group` is created for each one. See [Different animations for different elements](#different_animations_for_different_elements) for an example. +- {{cssxref("::view-transition-old")}} targets the static snapshot of the old page element, and {{cssxref("::view-transition-new")}} targets the live snapshot of the new page element. Both of these render as replaced content, in the same manner as an {{htmlelement("img")}} or {{htmlelement("video")}}, meaning that they can be styled with handy properties like {{cssxref("object-fit")}} and {{cssxref("object-position")}}. > **Note:** As you'll see later, to customize the outbound and inbound animations you need to target the {{cssxref("::view-transition-old")}} and {{cssxref("::view-transition-new")}} pseudo-elements with your animations, respectively. @@ -90,7 +93,7 @@ This code is enough to handle the transition between displayed images. Supportin ### Basic MPA view transition -When creating a cross-document (MPA) view transition, the process is even simpler than for SPAs — no JavaScript is required, as the view update is triggered by a document navigation rather than a JavaScript-initiated DOM change. To enable a basic MPA view transition, you need to specify a {{cssxref("@view-transition")}} at-rule in the CSS for both the current and destination documents to opt them in, like so: +When creating a cross-document (MPA) view transition, the process is even simpler than for SPAs. No JavaScript is required, as the view update is triggered by a cross-document, same-origin navigation rather than a JavaScript-initiated DOM change. To enable a basic MPA view transition, you need to specify a {{cssxref("@view-transition")}} at-rule in the CSS for both the current and destination documents to opt them in, like so: ```css @view-transition { @@ -122,7 +125,17 @@ For example, to change the speed of both: } ``` -In the case of cross-document (MPA) transitions, the CSS needs to be included in the current _and_ destination documents. You might think that you can just target `::view-transition-old(root)` in the current document and `::view-transition-new(root)` in the destination document but this results in some strange behavior, plus you'll probably want to navigate in the other direction at some point, in which case the old current document will become the new destination document, and the old destination document will become the new current document. +It is recommended that you target the `::view-transition-group()` with such styles in cases where you want to apply them to `::view-transition-old()` and `::view-transition-new()`. Because of the pseudo-element hierarchy and default user-agent styling, the styles will be inherited by both. For example: + +```css +::view-transition-group(root) { + animation-duration: 0.5s; +} +``` + +> **Note:** This is also a good option for safeguarding your code — `::view-transition-group()` also animates and you could end up with different durations for the `group`/`image-pair` pseudo-elements versus the `old` and `new` pseudo-elements. + +In the case of cross-document (MPA) transitions, the pseudo-elements need to be included in the destination document only for the view transition to work. If you want to use the view transition in both directions, you'll need to include it in both, of course. Our [View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transitions/mpa/) includes the above CSS, but takes the customization a step further, defining custom animations and applying them to the `::view-transition-old(root)` and `::view-transition-new(root)` pseudo-elements. The result is that the default cross-fade transition is swapped out for a "swipe up" transition when navigation occurs: @@ -160,7 +173,7 @@ Our [View Transitions MPA demo](https://mdn.github.io/dom-examples/view-transiti } ``` -## Different transitions for different elements +## Different animations for different elements By default, all of the different elements that change during the view update are transitioned using the same animation. If you want some elements to animate differently from the default `root` animation, you can separate them out using the {{cssxref("view-transition-name")}} property. For example, in our [View Transitions SPA demo](https://mdn.github.io/dom-examples/view-transitions/spa/) the {{htmlelement("figcaption")}} elements are given a `view-transition-name` of `figure-caption` to separate them from the rest of the page in terms of view transitions: @@ -211,8 +224,7 @@ The following code applies a custom animation just to the `
`: } } -::view-transition-old(figure-caption), -::view-transition-new(figure-caption) { +::view-transition-group(figure-caption) { height: auto; right: 0; left: auto; @@ -230,6 +242,14 @@ The following code applies a custom animation just to the `
`: Here we've created a custom CSS animation and applied it to the `::view-transition-old(figure-caption)` and `::view-transition-new(figure-caption)` pseudo-elements. We've also added a number of other styles to both to keep them in the same place and stop the default styling from interfering with our custom animations. +> **Note:** You can use `*` as the identifier in a pseudo-element to target all snapshot pseudo-elements, regardless of what name they have. For example: +> +> ```css +> ::view-transition-group(*) { +> animation-duration: 2s; +> } +> ``` + ### Taking advantage of the default animation styles Note that we also discovered another transition option that is simpler and produced a nicer result than the above. Our final `
` view transition ended up looking like this: @@ -239,8 +259,7 @@ figcaption { view-transition-name: figure-caption; } -::view-transition-old(figure-caption), -::view-transition-new(figure-caption) { +::view-transition-group(figure-caption) { height: 100%; } ``` @@ -337,8 +356,6 @@ The [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/p The JavaScript starts like this, defining the homepage path and creating {{domxref("URLPattern")}}s to represent the homepage and profile pages: ```js -// Path where this app is deployed. Because we don’t deploy at the root of the domain -// we need to keep track of this and adjust any URL matching using this value. const basePath = "/profiles/mpa"; const homePagePattern = new URLPattern(`${basePath}/`, window.origin); @@ -355,7 +372,7 @@ In this block we: - Grab the URL of the inbound document in the navigation from the {{domxref("NavigationHistoryEntry")}} object available at {{domxref("NavigationActivation.entry", "PageSwapEvent.activation.entry")}}. - Skip the transition if the inbound document's URL does not start with the same `basePath` as the current document. This is done using the {{domxref("ViewTransition.skipTransition()", "skipTransition()")}} method of the {{domxref("ViewTransition")}} object available at {{domxref("PageSwapEvent.viewTransition")}}. - Extract the profile name from the inbound URL using the `profilePagePattern`. -- Return out of the event listener if there is no profile name, i.e. the link is not navigating to a profile page. In this case, we don't want to customize the view transitions. +- Return out of the event listener if there is no profile name, i.e. the link is not navigating to a profile page. In this case, we don't want to customize the view transition animations. - Set view transition names on the relevant profile name and avatar so that they are animated during the navigation, and remove previously set view transition names to tidy up and ensure that the wrong elements do not animate. ```js @@ -407,7 +424,7 @@ window.addEventListener("pageswap", async (e) => { }); ``` -The {{domxref("Window.pagereveal_event", "pagereveal")}} event listener looks as follows. This works in a similar way to the `pageswap` event listener, although bear in mind that here we are customizing to "to" animation, for page elements on the inbound page. In this case, we: +The {{domxref("Window.pagereveal_event", "pagereveal")}} event listener looks as follows. This works in a similar way to the `pageswap` event listener, although bear in mind that here we are customizing the "to" animation, for page elements on the new page. In this case, we: - Return out of the event listener if there is no {{domxref("NavigationActivation.from", "PageSwapEvent.activation.from")}} history entry. We don't want an animation if we are going straight to the page and not navigation from somewhere else. - grab the "from" and "to" (current) URLs from the {{domxref("NavigationHistoryEntry")}} objects available at {{domxref("NavigationActivation.from", "PageRevealEvent.activation.from")}} and {{domxref("NavigationActivation.entry", "PageRevealEvent.activation.entry")}}. @@ -451,15 +468,37 @@ window.addEventListener("pagereveal", async (e) => { }); ``` -## Making cross-document transitions consistent with `rel="expect"` +## Stabilizing page state to make cross-document transitions consistent -[``](/en-US/docs/Web/HTML/Attributes/rel#expect) allows you to specify the most critical content in the associated document for the user's initial view of the page. Document rendering can be blocked until the specified content has been parsed, avoiding layout shifts and flashes when loading, and ensuring a consistent first paint across all supporting browsers. This is important for view transitions — a different first paint could result in a vastly different transition animation. +Before running a cross-document transition, you ideally want to wait until the state of the page stabilizes, relying on [render blocking](/en-US/docs/Glossary/Render_blocking) to ensure that: -Let's explore how this works with a simple example HTML document: +1. Critical styles are loaded and applied. +2. Critical scripts are loaded and run. +3. The HTML visible for the user's initial view of the page has been parsed and is visible. + +Styles are render blocked by default, and scripts can be render blocked using the [`blocking="render"`](/en-US/docs/Web/HTML/Attributes/rel#blocking) attribute. + +To ensure that your initial HTML has been parsed and is visible before the transition animation runs, you can use [``](/en-US/docs/Web/HTML/Attributes/rel#expect). In this element, you include the following attributes: + +- `rel="expect"` to indicate that you want to use this `` element to render block some HTML on the page. +- `href="#element-id"` to indicate the ID of the elment you want to render block. +- `blocking="render"` to render block the specified HTML. + +Let's explore what this looks like with a simple example HTML document: ```html + + + + + + +

Page title

@@ -472,17 +511,7 @@ Let's explore how this works with a simple example HTML document: ``` -Note the `` line: - -```html - -``` - -- `rel="expect"` tells the browser that we are expecting to block a specific action on a particular part of the page being parsed. -- `href="#lead-content"` specifies the ID of the element we want to block on. In this case, we are blocking the action until the {{htmlelement("div")}} element and its contents have been parsed. -- [`blocking="render"`](/en-US/docs/Web/HTML/Attributes/rel#blocking) specifies that the action we will block is the rendering of the document. - -The result is that document rendering is blocked until the lead content `
` has been parsed, ensuring consistency in first paint and view transitions. +The result is that document rendering is blocked until the lead content `
` has been parsed, ensuring a consistent view transition. You can also specify a [`media`](/en-US/docs/Web/HTML/Attributes/rel#blocking) attribute on `` elements. For example, you might want to block rendering on a smaller amount of content when loading the page on a narrow-screen device, than on a wide-screen device. This makes sense — on a mobile, less content will be visible when the page first loads than in the case of a desktop. diff --git a/files/en-us/web/api/viewtransition/skiptransition/index.md b/files/en-us/web/api/viewtransition/skiptransition/index.md index 5701e99f0880b3a..70b73126ffbe371 100644 --- a/files/en-us/web/api/viewtransition/skiptransition/index.md +++ b/files/en-us/web/api/viewtransition/skiptransition/index.md @@ -13,9 +13,6 @@ browser-compat: api.ViewTransition.skipTransition The **`skipTransition()`** method of the {{domxref("ViewTransition")}} interface skips the animation part of the view transition, but doesn't skip running the associated view update. -- In the case of a same-origin (SPA) transition, this would be triggered by the invocation of the {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} callback that updates the DOM. -- In the case of a cross-origin (MPA) transition, this would be triggered by a page navigation. - ## Syntax ```js-nolint diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index bf7d8256a1fd2d5..165d7aff25295ec 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -10,7 +10,7 @@ browser-compat: api.Window.pageswap_event {{APIRef("HTML DOM")}}{{seecompattable}} -The **`pageswap`** event is fired when a document is about to be unloaded due to a navigation. +The **`pageswap`** event is fired when you navigate across documents, when the previous document is about to unload. This is useful in the case of cross-document (MPA) [view transitions](/en-US/docs/Web/API/View_Transitions_API) for manipulating an active transition from the outbound page of a navigation. For example, you might wish to skip the transition, or customize the outbound transition animation via JavaScript. diff --git a/files/en-us/web/css/@view-transition/index.md b/files/en-us/web/css/@view-transition/index.md index cccd7aee307d726..87983e973d0de9d 100644 --- a/files/en-us/web/css/@view-transition/index.md +++ b/files/en-us/web/css/@view-transition/index.md @@ -9,6 +9,8 @@ browser-compat: css.at-rules.view-transition The **`@view-transition`** [CSS](/en-US/docs/Web/CSS) [at-rule](/en-US/docs/Web/CSS/At-rule) is used to opt in the current and destination documents to undergo a [view transition](/en-US/docs/Web/API/View_Transitions_API), in the case of a cross-document navigation. +For a cross-document view transition to work, the current and destination documents of the navigation also need to be on the same origin. + ## Syntax ```css @@ -23,7 +25,7 @@ The **`@view-transition`** [CSS](/en-US/docs/Web/CSS) [at-rule](/en-US/docs/Web/ - : Specifies the effect this at-rule will have on the document's view transition behavior. Possible values are: - - `auto`: The document will undergo a view transition when taking part in a navigation, provided the navigation is same-origin, without cross-origin redirects, and its {{domxref("NavigateEvent.navigationType", "navigationType")}} is `traverse`, `push`, or `replace`. In the case of `replace`, the navigation must be initiated by a user interacting with the page content, not by a browser UI feature. + - `auto`: The document will undergo a view transition when taking part in a navigation, provided the navigation is same-origin, without cross-origin redirects, and its {{domxref("NavigateEvent.navigationType", "navigationType")}} is `traverse`, `push`, or `replace`. In the case of `push` or `replace`, the navigation must be initiated by a user interacting with the page content, not by a browser UI feature. - `none`: The document will not undergo a view transition. diff --git a/files/en-us/web/css/_doublecolon_view-transition-group/index.md b/files/en-us/web/css/_doublecolon_view-transition-group/index.md index 93a0cf19c8436e2..b53a358486394b5 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-group/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-group/index.md @@ -9,7 +9,7 @@ browser-compat: css.selectors.view-transition-group {{CSSRef}}{{SeeCompatTable}} -The **`::view-transition-group`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents a single view transition group. +The **`::view-transition-group`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents a single view transition snapshot group. During a view transition, `::view-transition-group` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree). It is only ever a child of {{cssxref("::view-transition")}}, and has a {{cssxref("::view-transition-image-pair")}} as a child. diff --git a/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md b/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md index cd20c0ecf09aef6..b04254c32b9f5cc 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-image-pair/index.md @@ -16,12 +16,13 @@ During a view transition, `::view-transition-image-pair` is included in the asso `::view-transition-image-pair` is given the following default styling in the UA stylesheet: ```css -html::view-transition-image-pair(*) { +:root::view-transition-image-pair(*) { position: absolute; inset: 0; animation-duration: inherit; animation-fill-mode: inherit; + animation-delay: inherit; } ``` diff --git a/files/en-us/web/css/_doublecolon_view-transition-new/index.md b/files/en-us/web/css/_doublecolon_view-transition-new/index.md index 6e3a4a80c4519a6..3662d509b1b3814 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-new/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-new/index.md @@ -9,7 +9,7 @@ browser-compat: css.selectors.view-transition-new {{CSSRef}}{{SeeCompatTable}} -The **`::view-transition-new`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the "new" view state of a view transition — a live representation of the state after the transition. +The **`::view-transition-new`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the "new" view state of a view transition — a snapshot live representation of the state after the transition. During a view transition, `::view-transition-new` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree). It is only ever a child of a {{cssxref("::view-transition-image-pair")}}, and never has any children. @@ -18,21 +18,32 @@ It is a replaced element and therefore can be manipulated with properties such a The following default styling is included in the UA stylesheet: ```css -@keyframes -ua-view-transition-fade-in { - from { - opacity: 0; - } -} - -html::view-transition-new(*) { +:root::view-transition-old(*), +:root::view-transition-new(*) { position: absolute; inset-block-start: 0; inline-size: 100%; block-size: auto; - animation-name: -ua-view-transition-fade-in; animation-duration: inherit; animation-fill-mode: inherit; + animation-delay: inherit; +} + +/* Keyframes for blending when there are 2 images */ +@keyframes -ua-mix-blend-mode-plus-lighter { + from { + mix-blend-mode: plus-lighter; + } + to { + mix-blend-mode: plus-lighter; + } +} + +@keyframes -ua-view-transition-fade-in { + from { + opacity: 0; + } } ``` @@ -51,9 +62,9 @@ html::view-transition-new(*) { - `*` - : Causes the pseudo-element to match all view transition groups. - `root` - - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page. This group includes any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. + - : Causes the pseudo-element to match the default `root` view transition snapshot group created by the user agent to contain the view transition for the overall page. This group includes any element not assigned to its own specific view transition snapshot group via the {{cssxref("view-transition-name")}} property. - {{cssxref("custom-ident")}} - - : Causes the pseudo-element to match a specific view transition group created by assigning the given {{cssxref("custom-ident")}} to an element via the {{cssxref("view-transition-name")}} property. + - : Causes the pseudo-element to match a specific view transition snapshot group created by assigning the given {{cssxref("custom-ident")}} to an element via the {{cssxref("view-transition-name")}} property. ## Examples diff --git a/files/en-us/web/css/_doublecolon_view-transition-old/index.md b/files/en-us/web/css/_doublecolon_view-transition-old/index.md index 8f0a2c54386ecde..1548307440ae049 100644 --- a/files/en-us/web/css/_doublecolon_view-transition-old/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition-old/index.md @@ -9,7 +9,7 @@ browser-compat: css.selectors.view-transition-old {{CSSRef}}{{SeeCompatTable}} -The **`::view-transition-old`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the "old" view state of a view transition — a static screenshot of the old view, before the transition. +The **`::view-transition-old`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the "old" view state of a view transition — a static snapshot of the old view, before the transition. During a view transition, `::view-transition-old` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree), provided there's an "old" view state to represent. It is only ever a child of a {{cssxref("::view-transition-image-pair")}}, and never has any children. @@ -18,21 +18,32 @@ It is a replaced element and therefore can be manipulated with properties such a The following default styling is included in the UA stylesheet: ```css -@keyframes -ua-view-transition-fade-out { - to { - opacity: 0; - } -} - -html::view-transition-old(*) { +:root::view-transition-old(*), +:root::view-transition-new(*) { position: absolute; inset-block-start: 0; inline-size: 100%; block-size: auto; - animation-name: -ua-view-transition-fade-out; animation-duration: inherit; animation-fill-mode: inherit; + animation-delay: inherit; +} + +/* Keyframes for blending when there are 2 images */ +@keyframes -ua-mix-blend-mode-plus-lighter { + from { + mix-blend-mode: plus-lighter; + } + to { + mix-blend-mode: plus-lighter; + } +} + +@keyframes -ua-view-transition-fade-out { + to { + opacity: 0; + } } ``` @@ -51,9 +62,9 @@ html::view-transition-old(*) { - `*` - : Causes the pseudo-element to match all view transition groups. - `root` - - : Causes the pseudo-element to match the default `root` view transition group created by the user agent to contain the view transition for the overall page. This group includes any element not assigned to its own specific view transition group via the {{cssxref("view-transition-name")}} property. + - : Causes the pseudo-element to match the default `root` view transition snapshot group created by the user agent to contain the view transition for the overall page. This group includes any element not assigned to its own specific view transition snapshot group via the {{cssxref("view-transition-name")}} property. - {{cssxref("custom-ident")}} - - : Causes the pseudo-element to match a specific view transition group created by assigning the given {{cssxref("custom-ident")}} to an element via the {{cssxref("view-transition-name")}} property. + - : Causes the pseudo-element to match a specific view transition snapshot group created by assigning the given {{cssxref("custom-ident")}} to an element via the {{cssxref("view-transition-name")}} property. ## Examples diff --git a/files/en-us/web/css/_doublecolon_view-transition/index.md b/files/en-us/web/css/_doublecolon_view-transition/index.md index c635fabf3524eeb..178c839d48936d3 100644 --- a/files/en-us/web/css/_doublecolon_view-transition/index.md +++ b/files/en-us/web/css/_doublecolon_view-transition/index.md @@ -9,7 +9,7 @@ browser-compat: css.selectors.view-transition {{CSSRef}}{{SeeCompatTable}} -The **`::view-transition`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the root of the [view transitions](/en-US/docs/Web/API/View_Transitions_API) overlay, which contains all view transitions and sits over the top of all other page content. +The **`::view-transition`** [CSS](/en-US/docs/Web/CSS) [pseudo-element](/en-US/docs/Web/CSS/Pseudo-elements) represents the root of the [view transitions](/en-US/docs/Web/API/View_Transitions_API) overlay, which contains all view transition snapshot groups and sits over the top of all other page content. During a view transition, `::view-transition` is included in the associated pseudo-element tree as explained in [The view transition pseudo-element tree](/en-US/docs/Web/API/View_Transitions_API/Using#the_view_transition_pseudo-element_tree). It is the top-level node of this tree, and has one or more {{cssxref("::view-transition-group")}}s as children. diff --git a/files/en-us/web/css/view-transition-name/index.md b/files/en-us/web/css/view-transition-name/index.md index 76c994bf2760ecb..7149b857b2445f5 100644 --- a/files/en-us/web/css/view-transition-name/index.md +++ b/files/en-us/web/css/view-transition-name/index.md @@ -26,6 +26,7 @@ view-transition-name: none; - {{cssxref("custom-ident")}} - : An identifying name that causes the selected element to participate in a separate [view transition](/en-US/docs/Web/API/View_Transitions_API) from the root view transition. The identifier must be unique. If two rendered elements have the same `view-transition-name` at the same time, {{domxref("ViewTransition.ready")}} will reject and the transition will be skipped. + > **Note:** The `` cannot be `auto`. - `none` - : The selected element will not participate in a view transition. diff --git a/files/en-us/web/html/attributes/rel/index.md b/files/en-us/web/html/attributes/rel/index.md index e651b10785aad63..496f81110e941bd 100644 --- a/files/en-us/web/html/attributes/rel/index.md +++ b/files/en-us/web/html/attributes/rel/index.md @@ -24,7 +24,7 @@ The following table lists some of the most important existing keywords. Every ke | [`canonical`](#canonical) | Preferred URL for the current document. | Link | Not allowed | Not allowed | | [`dns-prefetch`](/en-US/docs/Web/HTML/Attributes/rel/dns-prefetch) | Tells the browser to preemptively perform DNS resolution for the target resource's origin. | External Resource | Not allowed | Not allowed | | [`external`](#external) | The referenced document is not part of the same site as the current document. | Not allowed | Annotation | Annotation | -| [`expect`](#expect) | Specifies content critical for the user's initial view of the page. Document rendering can be blocked until the specified content has been parsed. | Link | Not allowed | Not allowed | +| [`expect`](#expect) | Allows the HTML visible for the user's initial view of the page to be render-blocked until it has been parsed and is visible. | Link | Not allowed | Not allowed | | [`help`](#help) | Link to context-sensitive help. | Link | Link | Link | | [`icon`](#icon) | An icon representing the current document. | External Resource | Not allowed | Not allowed | | [`license`](#license) | Indicates that the main content of the current document is covered by the copyright license described by the referenced document. | Link | Link | Link | @@ -119,24 +119,10 @@ The `rel` attribute has no default value. If the attribute is omitted or if none - : Valid for {{htmlelement('link')}}, it defines the preferred URL for the current document, which helps search engines reduce duplicate content. - `dns-prefetch` - : Relevant for the {{htmlelement('link')}} element both in the {{htmlelement('body')}} and {{htmlelement('head')}}, it tells the browser to preemptively perform DNS resolution for the target resource's origin. Useful for resources the user will likely need, it helps reduce latency and thereby improves performance when the user does access the resources as the browser preemptively performed DNS resolution for the origin of the specified resource. See [dns-prefetch](/en-US/docs/Web/Performance/dns-prefetch) described in [resource hints](https://w3c.github.io/resource-hints/). -- `expect` - - - : `` allows you to specify the most critical content in the associated document for the user's initial view of the page. Document rendering can be blocked until the specified content has been parsed, avoiding layout shifts and flashes when loading, and ensuring a consistent first paint across all supporting browsers. This is important for [view transitions](/en-US/docs/Web/API/View_Transitions_API) — a different first paint could result in a vastly different transition animation. - - A typical example is as follows: - - ```html - - ``` - - - `rel="expect"` tells the browser that we are expecting to block a specific action on a particular part of the page being parsed. - - [`href="#lead-content"`](/en-US/docs/Web/HTML/Element/link#href) specifies the ID of the element we want to block on. In this case, we are blocking the action until the element with an `id` of `lead-content` and its contents have been parsed. - - [`blocking="render"`](/en-US/docs/Web/HTML/Element/link#blocking) specifies that the action we will block is the rendering of the document. - - See [Making cross-document transitions consistent with `rel="expect"`](/en-US/docs/Web/API/View_Transitions_API/Using#making_cross-document_transitions_consistent_with_relexpect) for a complete example. - - `external` - : Relevant to {{htmlelement('form')}}, {{htmlelement('a')}}, and {{htmlelement('area')}}, it indicates the referenced document is not part of the current site. This can be used with attribute selectors to style external links in a way that indicates to the user that they will be leaving the current site. +- `expect` + - : Allows the HTML visible for the user's initial view of the page to be [render-blocked](/en-US/docs/Glossary/Render_blocking) until it has been parsed and is visible. See [Stabilizing page state to make cross-document transitions consistent](/en-US/docs/Web/API/View_Transitions_API/Using#stabilizing_page_state_to_make_cross-document_transitions_consistent) for more information. - `help` - : Relevant to {{htmlelement('form')}}, {{htmlelement('link')}}, {{htmlelement('a')}}, and {{htmlelement('area')}}, the `help` keyword indicates that the linked to content provides context-sensitive help, providing information for the parent of the element defining the hyperlink, and its children. When used within ``, the help is for the whole document. When included with {{htmlelement('a')}} and {{htmlelement('area')}} and supported, the default {{cssxref('cursor')}} will be `help` instead of `pointer`. - `icon` From 0973ce2e56cc9e50d5a13696d7f64ab0121dddb5 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 24 Apr 2024 20:56:06 +0100 Subject: [PATCH 14/53] Update some details of rel=expect --- files/en-us/web/api/view_transitions_api/using/index.md | 4 ++-- files/en-us/web/html/attributes/rel/index.md | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 200dc040a358004..de232b0529628e6 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -474,11 +474,11 @@ Before running a cross-document transition, you ideally want to wait until the s 1. Critical styles are loaded and applied. 2. Critical scripts are loaded and run. -3. The HTML visible for the user's initial view of the page has been parsed and is visible. +3. The HTML visible for the user's initial view of the page has been parsed, so it renders consistently. Styles are render blocked by default, and scripts can be render blocked using the [`blocking="render"`](/en-US/docs/Web/HTML/Attributes/rel#blocking) attribute. -To ensure that your initial HTML has been parsed and is visible before the transition animation runs, you can use [``](/en-US/docs/Web/HTML/Attributes/rel#expect). In this element, you include the following attributes: +To ensure that your initial HTML has been parsed and will always render consistently before the transition animation runs, you can use [``](/en-US/docs/Web/HTML/Attributes/rel#expect). In this element, you include the following attributes: - `rel="expect"` to indicate that you want to use this `` element to render block some HTML on the page. - `href="#element-id"` to indicate the ID of the elment you want to render block. diff --git a/files/en-us/web/html/attributes/rel/index.md b/files/en-us/web/html/attributes/rel/index.md index 496f81110e941bd..97396c275a7385e 100644 --- a/files/en-us/web/html/attributes/rel/index.md +++ b/files/en-us/web/html/attributes/rel/index.md @@ -24,7 +24,7 @@ The following table lists some of the most important existing keywords. Every ke | [`canonical`](#canonical) | Preferred URL for the current document. | Link | Not allowed | Not allowed | | [`dns-prefetch`](/en-US/docs/Web/HTML/Attributes/rel/dns-prefetch) | Tells the browser to preemptively perform DNS resolution for the target resource's origin. | External Resource | Not allowed | Not allowed | | [`external`](#external) | The referenced document is not part of the same site as the current document. | Not allowed | Annotation | Annotation | -| [`expect`](#expect) | Allows the HTML visible for the user's initial view of the page to be render-blocked until it has been parsed and is visible. | Link | Not allowed | Not allowed | +| [`expect`](#expect) | Allows the HTML at the top of the page to be render-blocked until it has been parsed so it will render consistently. | Link | Not allowed | Not allowed | | [`help`](#help) | Link to context-sensitive help. | Link | Link | Link | | [`icon`](#icon) | An icon representing the current document. | External Resource | Not allowed | Not allowed | | [`license`](#license) | Indicates that the main content of the current document is covered by the copyright license described by the referenced document. | Link | Link | Link | @@ -122,7 +122,11 @@ The `rel` attribute has no default value. If the attribute is omitted or if none - `external` - : Relevant to {{htmlelement('form')}}, {{htmlelement('a')}}, and {{htmlelement('area')}}, it indicates the referenced document is not part of the current site. This can be used with attribute selectors to style external links in a way that indicates to the user that they will be leaving the current site. - `expect` - - : Allows the HTML visible for the user's initial view of the page to be [render-blocked](/en-US/docs/Glossary/Render_blocking) until it has been parsed and is visible. See [Stabilizing page state to make cross-document transitions consistent](/en-US/docs/Web/API/View_Transitions_API/Using#stabilizing_page_state_to_make_cross-document_transitions_consistent) for more information. + + - : Allows the HTML at the top of the page to be [render-blocked](/en-US/docs/Glossary/Render_blocking) until it has been parsed so it will render consistently. Note that render-blocking occurs only when supplemented with the [`blocking="render"`](/en-US/docs/Web/HTML/Attributes/rel#blocking) attribute. + + > **Note:** See [Stabilizing page state to make cross-document transitions consistent](/en-US/docs/Web/API/View_Transitions_API/Using#stabilizing_page_state_to_make_cross-document_transitions_consistent) for more information on its use. + - `help` - : Relevant to {{htmlelement('form')}}, {{htmlelement('link')}}, {{htmlelement('a')}}, and {{htmlelement('area')}}, the `help` keyword indicates that the linked to content provides context-sensitive help, providing information for the parent of the element defining the hyperlink, and its children. When used within ``, the help is for the whole document. When included with {{htmlelement('a')}} and {{htmlelement('area')}} and supported, the default {{cssxref('cursor')}} will be `help` instead of `pointer`. - `icon` From 3a508221fcc904173686606a42c012d2a1c1d89f Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 24 Apr 2024 21:03:59 +0100 Subject: [PATCH 15/53] Add note back in that was recently added to main --- files/en-us/web/api/view_transitions_api/using/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index de232b0529628e6..8ebc1f9d5788041 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -34,6 +34,9 @@ Let's walk through the process by which a view transition works: 5. The old page snapshots animate "out", while the new view snapshots animate "in". By default, the old view snapshots animate from {{cssxref("opacity")}} 1 to 0, and the new view snapshots animate from `opacity` 0 to 1, which creates a cross-fade. 6. When the transition animations have reached their end states, the {{domxref("ViewTransition.finished")}} promise fulfills, allowing you to respond. +> **Note:** +> If the document's [page visibility state](/en-US/docs/Web/API/Page_Visibility_API) is `hidden` (for example if the document is obscured by a window, the browser is minimized, or another browser tab is active) during a {{domxref("Document.startViewTransition()", "document.startViewTransition()")}} call, the view transition is skipped entirely. + ### The view transition pseudo-element tree To handle creating the outbound and inbound transition animations, the API constructs a pseudo-element tree with the following structure: From 4f19f174f08c53925598bfddb01767912c298dd3 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:48:30 +0100 Subject: [PATCH 16/53] Latest fixes to review comments --- .../api/navigationactivation/entry/index.md | 2 +- .../api/navigationactivation/from/index.md | 2 +- .../web/api/navigationactivation/index.md | 49 ++++-- files/en-us/web/api/pagerevealevent/index.md | 60 +++++--- .../pagerevealevent/viewtransition/index.md | 4 +- .../web/api/pageswapevent/activation/index.md | 6 +- files/en-us/web/api/pageswapevent/index.md | 63 ++++---- .../api/pageswapevent/viewtransition/index.md | 4 +- .../api/view_transitions_api/using/index.md | 143 ++++++++---------- .../web/api/window/pagereveal_event/index.md | 43 +++--- .../web/api/window/pageswap_event/index.md | 57 +++---- files/en-us/web/html/attributes/rel/index.md | 4 +- 12 files changed, 223 insertions(+), 214 deletions(-) diff --git a/files/en-us/web/api/navigationactivation/entry/index.md b/files/en-us/web/api/navigationactivation/entry/index.md index 58bd91020640b54..09ba309845a24d4 100644 --- a/files/en-us/web/api/navigationactivation/entry/index.md +++ b/files/en-us/web/api/navigationactivation/entry/index.md @@ -20,7 +20,7 @@ A {{domxref("NavigationHistoryEntry")}} object. ## Examples -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. +See the main {{domxref("NavigationActivation")}} page. ## Specifications diff --git a/files/en-us/web/api/navigationactivation/from/index.md b/files/en-us/web/api/navigationactivation/from/index.md index a855ba86914187d..682834b202b24de 100644 --- a/files/en-us/web/api/navigationactivation/from/index.md +++ b/files/en-us/web/api/navigationactivation/from/index.md @@ -21,7 +21,7 @@ A {{domxref("NavigationHistoryEntry")}} object, or `null` if the outgoing docume ## Examples -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. +See the main {{domxref("NavigationActivation")}} page. ## Specifications diff --git a/files/en-us/web/api/navigationactivation/index.md b/files/en-us/web/api/navigationactivation/index.md index c46c4bac9c0021f..a528de33dcebe70 100644 --- a/files/en-us/web/api/navigationactivation/index.md +++ b/files/en-us/web/api/navigationactivation/index.md @@ -25,24 +25,45 @@ This object is accessed via the {{domxref("PageSwapEvent.activation")}} and {{do ## Examples ```js -window.addEventListener("pageswap", (event) => { - // Return if there is no active view transition - if (!event.viewTransition) { - return; - } - - // Grab the paths of the from and to URLs - const from_path = new URL(event.activation.from).pathname; - const to_path = new URL(event.activation.entry).pathname; - - // Skip transitions from landing to home - if (from_path === "/landing" && to_path === "/home") { - event.viewTransition.skipTransition(); +window.addEventListener('pagereveal', async (e) => { + // If the "from" history entry does not exist, return + if (!navigation.activation.from) return; + + // Only run this if an active view transition exists + if (e.viewTransition) { + const fromUrl = new URL(navigation.activation.from.url); + const currentUrl = new URL(navigation.activation.entry.url); + + // Only transition to/from same basePath + // ~> SKIP! + if (!fromUrl.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } + + // Went from profile page to homepage + // ~> Set VT names on the relevant list item + if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { + const profile = extractProfileNameFromUrl(fromUrl); + + setTemporaryViewTransitionNames([ + [document.querySelector(`#${profile} span`), 'name'], + [document.querySelector(`#${profile} img`), 'avatar'], + ], e.viewTransition.ready); + } + + // Went to profile page + // ~> Set VT names on the main title and image + if (isProfilePage(currentUrl)) { + setTemporaryViewTransitionNames([ + [document.querySelector(`#detail main h1`), 'name'], + [document.querySelector(`#detail main img`), 'avatar'], + ], e.viewTransition.ready); + } } }); ``` -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example. +> **Note:** See [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) for the live demo this code is taken from. ## Specifications diff --git a/files/en-us/web/api/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/index.md index b02beb9983d3f73..afa1727fe308afa 100644 --- a/files/en-us/web/api/pagerevealevent/index.md +++ b/files/en-us/web/api/pagerevealevent/index.md @@ -13,6 +13,19 @@ The **`PageRevealEvent`** event object is made available inside handler function During a cross-document navigation, it allows you to manipulate a related [view transition](/en-US/docs/Web/API/View_Transitions_API) (providing access to the relevant {{domxref("ViewTransition")}} object) from the document being navigated _to_, if a view transition was triggered by the navigation. +Outside view transitions, this event is also useful for cases such as triggering a startup animation, or reporting a page view. It's equivalent to the first {{domxref("Window.requestAnimationFrame()")}} run after a cross-document navigation, if you were to trigger `requestAnimationFrame()` in the {{htmlelement("head")}} of the document. For example, if you ran the following `reveal()` function in the ``: + +```js +function reveal() { + // Include startup animation here +} +/* This will fire in the first rendered frame after loading */ +requestAnimationFrame(() => reveal()); + +/* This will fire if the page is restored from BFCache */ +window.onpagehide = () => requestAnimationFrame(() => reveal()); +``` + ## Constructor - {{domxref("PageRevealEvent.PageRevealEvent", "PageRevealEvent()")}} @@ -26,36 +39,45 @@ During a cross-document navigation, it allows you to manipulate a related [view ## Examples ```js -// When going from a detail page to the homepage, set `profile-name` and `profile-avatar` vt-names -// on the list item for the profile that was viewed on the detail page. -window.addEventListener("pagereveal", async (e) => { +window.addEventListener('pagereveal', async (e) => { + // If the "from" history entry does not exist, return if (!navigation.activation.from) return; + // Only run this if an active view transition exists if (e.viewTransition) { - const fromURL = new URL(navigation.activation.from.url); - const currentURL = new URL(navigation.activation.entry.url); + const fromUrl = new URL(navigation.activation.from.url); + const currentUrl = new URL(navigation.activation.entry.url); + + // Only transition to/from same basePath + // ~> SKIP! + if (!fromUrl.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } // Went from profile page to homepage // ~> Set VT names on the relevant list item - if (profilePagePattern.test(fromURL) && homePagePattern.test(currentURL)) { - const match = profilePagePattern.exec(fromURL); - const profile = match?.pathname.groups.profile; - - document.querySelector(`#${profile} span`).style.viewTransitionName = - "profile-name"; - document.querySelector(`#${profile} img`).style.viewTransitionName = - "profile-avatar"; - - // Clean up after snapshots have been taken - await e.viewTransition.ready; - document.querySelector(`#${profile} span`).style.viewTransitionName = ""; - document.querySelector(`#${profile} img`).style.viewTransitionName = ""; + if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { + const profile = extractProfileNameFromUrl(fromUrl); + + setTemporaryViewTransitionNames([ + [document.querySelector(`#${profile} span`), 'name'], + [document.querySelector(`#${profile} img`), 'avatar'], + ], e.viewTransition.ready); + } + + // Went to profile page + // ~> Set VT names on the main title and image + if (isProfilePage(currentUrl)) { + setTemporaryViewTransitionNames([ + [document.querySelector(`#detail main h1`), 'name'], + [document.querySelector(`#detail main img`), 'avatar'], + ], e.viewTransition.ready); } } }); ``` -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example with explanations. +> **Note:** See [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) for the live demo this code is taken from. ## Specifications diff --git a/files/en-us/web/api/pagerevealevent/viewtransition/index.md b/files/en-us/web/api/pagerevealevent/viewtransition/index.md index 45f83727bd68657..c8ae71d6b4b284a 100644 --- a/files/en-us/web/api/pagerevealevent/viewtransition/index.md +++ b/files/en-us/web/api/pagerevealevent/viewtransition/index.md @@ -1,6 +1,6 @@ --- title: "PageRevealEvent: viewTransition property" -short-title: from +short-title: viewTransition slug: Web/API/PageRevealEvent/viewTransition page-type: web-api-instance-property status: @@ -18,7 +18,7 @@ A {{domxref("ViewTransition")}} object, or `null` if no view transition is activ ## Examples -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. +See the main {{domxref("PageRevealEvent")}} page. ## Specifications diff --git a/files/en-us/web/api/pageswapevent/activation/index.md b/files/en-us/web/api/pageswapevent/activation/index.md index dcae7bf859b792f..ad5231f67d895dd 100644 --- a/files/en-us/web/api/pageswapevent/activation/index.md +++ b/files/en-us/web/api/pageswapevent/activation/index.md @@ -1,11 +1,11 @@ --- title: "PageSwapEvent: activation property" -short-title: from +short-title: activation slug: Web/API/PageSwapEvent/activation page-type: web-api-instance-property status: - experimental -browser-compat: api.PageSwapEvent.viewTransition +browser-compat: api.PageSwapEvent.activation --- {{APIRef("HTML DOM")}}{{SeeCompatTable}} @@ -18,7 +18,7 @@ A {{domxref("NavigationActivation")}} object, or `null` if the associated naviga ## Examples -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. +See the main {{domxref("PageSwapEvent")}} page. ## Specifications diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index a1f3c6ca0a54b7b..02f9fc1b555c587 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -28,49 +28,42 @@ The pageswap event is fired when you navigate across documents, when the previou ## Examples ```js -// When going to a detail page, set `profile-name` and `profile-avatar` vt-names -// on the elements that link to that detail page -window.addEventListener("pageswap", async (e) => { +window.addEventListener('pageswap', async (e) => { + // Only run this if an active view transition exists if (e.viewTransition) { - const url = new URL(e.activation.entry.url); - - // Extract name from URL - const match = profilePagePattern.exec(url); - const profile = match?.pathname.groups.profile; - - // No name extract = not going to a detail page - // ~> Don’t tweak VT - if (!profile) return; - - // Set VT-names on clicked name - document.querySelector(`#${profile} span`).style.viewTransitionName = - "profile-name"; - document.querySelector(`#${profile} img`).style.viewTransitionName = - "profile-avatar"; - - // Remove VT-names from currently shown ones when already at a detail page - // @TODO: Figure out why I had to set to x and y here, instead of just '' - if (profilePagePattern.test(window.location.href)) { - document.querySelector(`main h1`).style.viewTransitionName = "x"; - document.querySelector(`main img`).style.viewTransitionName = "y"; + const currentUrl = e.activation.from?.url ? new URL(e.activation.from.url) : null; + const targetUrl = new URL(e.activation.entry.url); + + // Only transition to same basePath + // ~> SKIP! + if (!targetUrl.pathname.startsWith(basePath)) { + e.viewTransition.skipTransition(); + } + + // Going from profile page to homepage + // ~> The big img and title are the ones! + if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { + setTemporaryViewTransitionNames([ + [document.querySelector(`#detail main h1`), 'name'], + [document.querySelector(`#detail main img`), 'avatar'], + ], e.viewTransition.finished); } - // Restore orig VT names after snapshots have been taken - // (This to deal with BFCache) - await e.viewTransition.finished; - document.querySelector(`#${profile} span`).style.viewTransitionName = "z"; - document.querySelector(`#${profile} img`).style.viewTransitionName = "w"; - if (profilePagePattern.test(window.location.href)) { - document.querySelector(`main h1`).style.viewTransitionName = - "profile-name"; - document.querySelector(`main img`).style.viewTransitionName = - "profile-avatar"; + // Going to profile page + // ~> The clicked items are the ones! + if (isProfilePage(targetUrl)) { + const profile = extractProfileNameFromUrl(targetUrl); + + setTemporaryViewTransitionNames([ + [document.querySelector(`#${profile} span`), 'name'], + [document.querySelector(`#${profile} img`), 'avatar'], + ], e.viewTransition.finished); } } }); ``` -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example with explanations. +> **Note:** See [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) for the live demo this code is taken from. ## Specifications diff --git a/files/en-us/web/api/pageswapevent/viewtransition/index.md b/files/en-us/web/api/pageswapevent/viewtransition/index.md index 598355d8ed52a42..350a758553abaf7 100644 --- a/files/en-us/web/api/pageswapevent/viewtransition/index.md +++ b/files/en-us/web/api/pageswapevent/viewtransition/index.md @@ -1,6 +1,6 @@ --- title: "PageSwapEvent: viewTransition property" -short-title: from +short-title: viewTransition slug: Web/API/PageSwapEvent/viewTransition page-type: web-api-instance-property status: @@ -18,7 +18,7 @@ A {{domxref("ViewTransition")}} object, or `null` if no view transition is activ ## Examples -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a complete example. +See the main {{domxref("PageSwapEvent")}} page. ## Specifications diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 8ebc1f9d5788041..5656204f368aa16 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -356,121 +356,104 @@ This animation also requires the following CSS, to turn off the default CSS anim The [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) demo provides a basic set of team profile pages, and demonstrates how to use the {{domxref("Window.pagereveal_event", "pagereveal")}} and {{domxref("Window.pageswap_event", "pageswap")}} events to customize the outgoing and inbound animations of a cross-document view transition based on the "from" and "to" URLs. -The JavaScript starts like this, defining the homepage path and creating {{domxref("URLPattern")}}s to represent the homepage and profile pages: - -```js -const basePath = "/profiles/mpa"; - -const homePagePattern = new URLPattern(`${basePath}/`, window.origin); -const profilePagePattern = new URLPattern( - `${basePath}/:profile`, - window.origin, -); -``` - The {{domxref("Window.pageswap_event", "pageswap")}} event listener looks as follows. This sets view transition names on the elements on the outbound page that link to the profile pages. When navigating from the home page to a profile page, custom animations are provided _only_ for the linked element that is clicked in each case. -In this block we: - -- Grab the URL of the inbound document in the navigation from the {{domxref("NavigationHistoryEntry")}} object available at {{domxref("NavigationActivation.entry", "PageSwapEvent.activation.entry")}}. -- Skip the transition if the inbound document's URL does not start with the same `basePath` as the current document. This is done using the {{domxref("ViewTransition.skipTransition()", "skipTransition()")}} method of the {{domxref("ViewTransition")}} object available at {{domxref("PageSwapEvent.viewTransition")}}. -- Extract the profile name from the inbound URL using the `profilePagePattern`. -- Return out of the event listener if there is no profile name, i.e. the link is not navigating to a profile page. In this case, we don't want to customize the view transition animations. -- Set view transition names on the relevant profile name and avatar so that they are animated during the navigation, and remove previously set view transition names to tidy up and ensure that the wrong elements do not animate. - ```js -// When going to a detail page, set `profile-name` and `profile-avatar` vt-names -// on the elements that link to that detail page -window.addEventListener("pageswap", async (e) => { +window.addEventListener('pageswap', async (e) => { + // Only run this if an active view transition exists if (e.viewTransition) { - const url = new URL(e.activation.entry.url); + const currentUrl = e.activation.from?.url ? new URL(e.activation.from.url) : null; + const targetUrl = new URL(e.activation.entry.url); // Only transition to same basePath // ~> SKIP! - if (!url.pathname.startsWith(basePath)) { + if (!targetUrl.pathname.startsWith(basePath)) { e.viewTransition.skipTransition(); } - // Extract name from URL - const match = profilePagePattern.exec(url); - const profile = match?.pathname.groups.profile; - - // No name extract = not going to a detail page - // ~> Don’t tweak VT - if (!profile) return; - - // Set VT-names on clicked name - document.querySelector(`#${profile} span`).style.viewTransitionName = - "profile-name"; - document.querySelector(`#${profile} img`).style.viewTransitionName = - "profile-avatar"; - - // Remove VT-names from currently shown ones when already at a detail page - // @TODO: Figure out why I had to set to x and y here, instead of just '' - if (profilePagePattern.test(window.location.href)) { - document.querySelector(`main h1`).style.viewTransitionName = "x"; - document.querySelector(`main img`).style.viewTransitionName = "y"; + // Going from profile page to homepage + // ~> The big img and title are the ones! + if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { + setTemporaryViewTransitionNames([ + [document.querySelector(`#detail main h1`), 'name'], + [document.querySelector(`#detail main img`), 'avatar'], + ], e.viewTransition.finished); } - // Restore orig VT names after snapshots have been taken - // (This to deal with BFCache) - await e.viewTransition.finished; - document.querySelector(`#${profile} span`).style.viewTransitionName = "z"; - document.querySelector(`#${profile} img`).style.viewTransitionName = "w"; - if (profilePagePattern.test(window.location.href)) { - document.querySelector(`main h1`).style.viewTransitionName = - "profile-name"; - document.querySelector(`main img`).style.viewTransitionName = - "profile-avatar"; + // Going to profile page + // ~> The clicked items are the ones! + if (isProfilePage(targetUrl)) { + const profile = extractProfileNameFromUrl(targetUrl); + + setTemporaryViewTransitionNames([ + [document.querySelector(`#${profile} span`), 'name'], + [document.querySelector(`#${profile} img`), 'avatar'], + ], e.viewTransition.finished); } } }); ``` -The {{domxref("Window.pagereveal_event", "pagereveal")}} event listener looks as follows. This works in a similar way to the `pageswap` event listener, although bear in mind that here we are customizing the "to" animation, for page elements on the new page. In this case, we: - -- Return out of the event listener if there is no {{domxref("NavigationActivation.from", "PageSwapEvent.activation.from")}} history entry. We don't want an animation if we are going straight to the page and not navigation from somewhere else. -- grab the "from" and "to" (current) URLs from the {{domxref("NavigationHistoryEntry")}} objects available at {{domxref("NavigationActivation.from", "PageRevealEvent.activation.from")}} and {{domxref("NavigationActivation.entry", "PageRevealEvent.activation.entry")}}. -- Skip the transition if the inbound document's URL does not start with the same `basePath` as the current document. This is done using the {{domxref("ViewTransition.skipTransition()", "skipTransition()")}} method of the {{domxref("ViewTransition")}} object available at {{domxref("PageSwapEvent.viewTransition")}}. -- Test the "from" and "to" (current) URLs using the `profilePagePattern` and `homePagePattern`, only running the next step if the "from" page is a profile page and the "to" page is the homepage. -- Set view transition names on the relevant list item features so that they are animated during the navigation, and remove previously set view transition names to tidy up and ensure that the wrong elements do not animate. +The {{domxref("Window.pagereveal_event", "pagereveal")}} event listener looks as follows. This works in a similar way to the `pageswap` event listener, although bear in mind that here we are customizing the "to" animation, for page elements on the new page. ```js -// When going from a detail page to the homepage, set `profile-name` and `profile-avatar` vt-names -// on the list item for the profile that was viewed on the detail page. -window.addEventListener("pagereveal", async (e) => { +window.addEventListener('pagereveal', async (e) => { + // If the "from" history entry does not exist, return if (!navigation.activation.from) return; + // Only run this if an active view transition exists if (e.viewTransition) { - const fromURL = new URL(navigation.activation.from.url); - const currentURL = new URL(navigation.activation.entry.url); + const fromUrl = new URL(navigation.activation.from.url); + const currentUrl = new URL(navigation.activation.entry.url); // Only transition to/from same basePath // ~> SKIP! - if (!fromURL.pathname.startsWith(basePath)) { + if (!fromUrl.pathname.startsWith(basePath)) { e.viewTransition.skipTransition(); } // Went from profile page to homepage // ~> Set VT names on the relevant list item - if (profilePagePattern.test(fromURL) && homePagePattern.test(currentURL)) { - const match = profilePagePattern.exec(fromURL); - const profile = match?.pathname.groups.profile; - - document.querySelector(`#${profile} span`).style.viewTransitionName = - "profile-name"; - document.querySelector(`#${profile} img`).style.viewTransitionName = - "profile-avatar"; - - // Clean up after snapshots have been taken - await e.viewTransition.ready; - document.querySelector(`#${profile} span`).style.viewTransitionName = ""; - document.querySelector(`#${profile} img`).style.viewTransitionName = ""; + if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { + const profile = extractProfileNameFromUrl(fromUrl); + + setTemporaryViewTransitionNames([ + [document.querySelector(`#${profile} span`), 'name'], + [document.querySelector(`#${profile} img`), 'avatar'], + ], e.viewTransition.ready); + } + + // Went to profile page + // ~> Set VT names on the main title and image + if (isProfilePage(currentUrl)) { + setTemporaryViewTransitionNames([ + [document.querySelector(`#detail main h1`), 'name'], + [document.querySelector(`#detail main img`), 'avatar'], + ], e.viewTransition.ready); } } }); ``` +The `setTemporaryViewTransitionNames()` user-defined function is used repeatedly in this code. This looks like so: + +```js +const setTemporaryViewTransitionNames = async (entries, vtPromise) => { + // Apply a custom view transition to each element passed into the function + for (const [$el, name] of entries) { + $el.style.viewTransitionName = name; + } + + // Await the view transition promise passed into the function, e.g. ready or finished + await vtPromise; + + // Remove the custom view transition from each element passed into the function + for (const [$el, name] of entries) { + $el.style.viewTransitionName = ''; + } +} +``` + ## Stabilizing page state to make cross-document transitions consistent Before running a cross-document transition, you ideally want to wait until the state of the page stabilizes, relying on [render blocking](/en-US/docs/Glossary/Render_blocking) to ensure that: diff --git a/files/en-us/web/api/window/pagereveal_event/index.md b/files/en-us/web/api/window/pagereveal_event/index.md index af075c6a7385736..ff53dc683bb34b1 100644 --- a/files/en-us/web/api/window/pagereveal_event/index.md +++ b/files/en-us/web/api/window/pagereveal_event/index.md @@ -37,42 +37,45 @@ A {{domxref("PageRevealEvent")}}. Inherits from {{domxref("Event")}}. ## Examples ```js -// When going from a detail page to the homepage, set `profile-name` and `profile-avatar` vt-names -// on the list item for the profile that was viewed on the detail page. -window.addEventListener("pagereveal", async (e) => { +window.addEventListener('pagereveal', async (e) => { + // If the "from" history entry does not exist, return if (!navigation.activation.from) return; + // Only run this if an active view transition exists if (e.viewTransition) { - const fromURL = new URL(navigation.activation.from.url); - const currentURL = new URL(navigation.activation.entry.url); + const fromUrl = new URL(navigation.activation.from.url); + const currentUrl = new URL(navigation.activation.entry.url); // Only transition to/from same basePath // ~> SKIP! - if (!fromURL.pathname.startsWith(basePath)) { + if (!fromUrl.pathname.startsWith(basePath)) { e.viewTransition.skipTransition(); } // Went from profile page to homepage // ~> Set VT names on the relevant list item - if (profilePagePattern.test(fromURL) && homePagePattern.test(currentURL)) { - const match = profilePagePattern.exec(fromURL); - const profile = match?.pathname.groups.profile; - - document.querySelector(`#${profile} span`).style.viewTransitionName = - "profile-name"; - document.querySelector(`#${profile} img`).style.viewTransitionName = - "profile-avatar"; - - // Clean up after snapshots have been taken - await e.viewTransition.ready; - document.querySelector(`#${profile} span`).style.viewTransitionName = ""; - document.querySelector(`#${profile} img`).style.viewTransitionName = ""; + if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { + const profile = extractProfileNameFromUrl(fromUrl); + + setTemporaryViewTransitionNames([ + [document.querySelector(`#${profile} span`), 'name'], + [document.querySelector(`#${profile} img`), 'avatar'], + ], e.viewTransition.ready); + } + + // Went to profile page + // ~> Set VT names on the main title and image + if (isProfilePage(currentUrl)) { + setTemporaryViewTransitionNames([ + [document.querySelector(`#detail main h1`), 'name'], + [document.querySelector(`#detail main img`), 'avatar'], + ], e.viewTransition.ready); } } }); ``` -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example with explanations. +> **Note:** See [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) for the live demo this code is taken from. ## Specifications diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index 165d7aff25295ec..93b25d1f4854d50 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -41,55 +41,42 @@ A {{domxref("PageSwapEvent")}}. Inherits from {{domxref("Event")}}. ## Examples ```js -// When going to a detail page, set `profile-name` and `profile-avatar` vt-names -// on the elements that link to that detail page -window.addEventListener("pageswap", async (e) => { +window.addEventListener('pageswap', async (e) => { + // Only run this if an active view transition exists if (e.viewTransition) { - const url = new URL(e.activation.entry.url); + const currentUrl = e.activation.from?.url ? new URL(e.activation.from.url) : null; + const targetUrl = new URL(e.activation.entry.url); // Only transition to same basePath // ~> SKIP! - if (!url.pathname.startsWith(basePath)) { + if (!targetUrl.pathname.startsWith(basePath)) { e.viewTransition.skipTransition(); } - // Extract name from URL - const match = profilePagePattern.exec(url); - const profile = match?.pathname.groups.profile; - - // No name extract = not going to a detail page - // ~> Don’t tweak VT - if (!profile) return; - - // Set VT-names on clicked name - document.querySelector(`#${profile} span`).style.viewTransitionName = - "profile-name"; - document.querySelector(`#${profile} img`).style.viewTransitionName = - "profile-avatar"; - - // Remove VT-names from currently shown ones when already at a detail page - // @TODO: Figure out why I had to set to x and y here, instead of just '' - if (profilePagePattern.test(window.location.href)) { - document.querySelector(`main h1`).style.viewTransitionName = "x"; - document.querySelector(`main img`).style.viewTransitionName = "y"; + // Going from profile page to homepage + // ~> The big img and title are the ones! + if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { + setTemporaryViewTransitionNames([ + [document.querySelector(`#detail main h1`), 'name'], + [document.querySelector(`#detail main img`), 'avatar'], + ], e.viewTransition.finished); } - // Restore orig VT names after snapshots have been taken - // (This to deal with BFCache) - await e.viewTransition.finished; - document.querySelector(`#${profile} span`).style.viewTransitionName = "z"; - document.querySelector(`#${profile} img`).style.viewTransitionName = "w"; - if (profilePagePattern.test(window.location.href)) { - document.querySelector(`main h1`).style.viewTransitionName = - "profile-name"; - document.querySelector(`main img`).style.viewTransitionName = - "profile-avatar"; + // Going to profile page + // ~> The clicked items are the ones! + if (isProfilePage(targetUrl)) { + const profile = extractProfileNameFromUrl(targetUrl); + + setTemporaryViewTransitionNames([ + [document.querySelector(`#${profile} span`), 'name'], + [document.querySelector(`#${profile} img`), 'avatar'], + ], e.viewTransition.finished); } } }); ``` -> **Note:** See [A JavaScript-powered custom cross-document (MPA) transition](/en-US/docs/Web/API/View_Transitions_API/Using#a_javascript-powered_custom_cross-document_mpa_transition) for a more complete example with explanations. +> **Note:** See [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) for the live demo this code is taken from. ## Specifications diff --git a/files/en-us/web/html/attributes/rel/index.md b/files/en-us/web/html/attributes/rel/index.md index 97396c275a7385e..00dc850c759086f 100644 --- a/files/en-us/web/html/attributes/rel/index.md +++ b/files/en-us/web/html/attributes/rel/index.md @@ -24,7 +24,7 @@ The following table lists some of the most important existing keywords. Every ke | [`canonical`](#canonical) | Preferred URL for the current document. | Link | Not allowed | Not allowed | | [`dns-prefetch`](/en-US/docs/Web/HTML/Attributes/rel/dns-prefetch) | Tells the browser to preemptively perform DNS resolution for the target resource's origin. | External Resource | Not allowed | Not allowed | | [`external`](#external) | The referenced document is not part of the same site as the current document. | Not allowed | Annotation | Annotation | -| [`expect`](#expect) | Allows the HTML at the top of the page to be render-blocked until it has been parsed so it will render consistently. | Link | Not allowed | Not allowed | +| [`expect`](#expect) | Allows the page to be [render-blocked](/en-US/docs/Glossary/Render_blocking) until the essential parts of the document are parsed so it will render consistently. | Link | Not allowed | Not allowed | | [`help`](#help) | Link to context-sensitive help. | Link | Link | Link | | [`icon`](#icon) | An icon representing the current document. | External Resource | Not allowed | Not allowed | | [`license`](#license) | Indicates that the main content of the current document is covered by the copyright license described by the referenced document. | Link | Link | Link | @@ -123,7 +123,7 @@ The `rel` attribute has no default value. If the attribute is omitted or if none - : Relevant to {{htmlelement('form')}}, {{htmlelement('a')}}, and {{htmlelement('area')}}, it indicates the referenced document is not part of the current site. This can be used with attribute selectors to style external links in a way that indicates to the user that they will be leaving the current site. - `expect` - - : Allows the HTML at the top of the page to be [render-blocked](/en-US/docs/Glossary/Render_blocking) until it has been parsed so it will render consistently. Note that render-blocking occurs only when supplemented with the [`blocking="render"`](/en-US/docs/Web/HTML/Attributes/rel#blocking) attribute. + - : Allows the page to be [render-blocked](/en-US/docs/Glossary/Render_blocking) until the essential parts of the document are parsed so it will render consistently. Note that render-blocking occurs only when supplemented with the [`blocking="render"`](/en-US/docs/Web/HTML/Attributes/rel#blocking) attribute. > **Note:** See [Stabilizing page state to make cross-document transitions consistent](/en-US/docs/Web/API/View_Transitions_API/Using#stabilizing_page_state_to_make_cross-document_transitions_consistent) for more information on its use. From b9a75307d3c31557f5f4bedb0200f40f358707b6 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:53:57 +0100 Subject: [PATCH 17/53] Update files/en-us/web/html/attributes/rel/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/html/attributes/rel/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/html/attributes/rel/index.md b/files/en-us/web/html/attributes/rel/index.md index 00dc850c759086f..1656462b78c3132 100644 --- a/files/en-us/web/html/attributes/rel/index.md +++ b/files/en-us/web/html/attributes/rel/index.md @@ -24,7 +24,7 @@ The following table lists some of the most important existing keywords. Every ke | [`canonical`](#canonical) | Preferred URL for the current document. | Link | Not allowed | Not allowed | | [`dns-prefetch`](/en-US/docs/Web/HTML/Attributes/rel/dns-prefetch) | Tells the browser to preemptively perform DNS resolution for the target resource's origin. | External Resource | Not allowed | Not allowed | | [`external`](#external) | The referenced document is not part of the same site as the current document. | Not allowed | Annotation | Annotation | -| [`expect`](#expect) | Allows the page to be [render-blocked](/en-US/docs/Glossary/Render_blocking) until the essential parts of the document are parsed so it will render consistently. | Link | Not allowed | Not allowed | +| [`expect`](#expect) | Allows the page to be [render-blocked](/en-US/docs/Glossary/Render_blocking) until the essential parts of the document are parsed so it will render consistently. | Link | Not allowed | Not allowed | | [`help`](#help) | Link to context-sensitive help. | Link | Link | Link | | [`icon`](#icon) | An icon representing the current document. | External Resource | Not allowed | Not allowed | | [`license`](#license) | Indicates that the main content of the current document is covered by the copyright license described by the referenced document. | Link | Link | Link | From 9e1d07449840d170d3efd9ab9232cbca5cc8d146 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:54:36 +0100 Subject: [PATCH 18/53] Update files/en-us/web/api/navigationactivation/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/navigationactivation/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/navigationactivation/index.md b/files/en-us/web/api/navigationactivation/index.md index a528de33dcebe70..c44910418201e42 100644 --- a/files/en-us/web/api/navigationactivation/index.md +++ b/files/en-us/web/api/navigationactivation/index.md @@ -25,7 +25,7 @@ This object is accessed via the {{domxref("PageSwapEvent.activation")}} and {{do ## Examples ```js -window.addEventListener('pagereveal', async (e) => { +window.addEventListener("pagereveal", async (e) => { // If the "from" history entry does not exist, return if (!navigation.activation.from) return; From 7fe0eaf8b2af63fc8b0621eec345eb0edfa29dc9 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:55:06 +0100 Subject: [PATCH 19/53] Update files/en-us/web/api/window/pageswap_event/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/window/pageswap_event/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index 93b25d1f4854d50..efb241e8c3cc89a 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -56,10 +56,13 @@ window.addEventListener('pageswap', async (e) => { // Going from profile page to homepage // ~> The big img and title are the ones! if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { - setTemporaryViewTransitionNames([ - [document.querySelector(`#detail main h1`), 'name'], - [document.querySelector(`#detail main img`), 'avatar'], - ], e.viewTransition.finished); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#detail main h1`), "name"], + [document.querySelector(`#detail main img`), "avatar"], + ], + e.viewTransition.finished, + ); } // Going to profile page From 0b142e5931593efaf006efa4a76140f2e175cb8b Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:55:46 +0100 Subject: [PATCH 20/53] Update files/en-us/web/api/window/pageswap_event/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/window/pageswap_event/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index efb241e8c3cc89a..52cdf710515d4bf 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -70,10 +70,13 @@ window.addEventListener('pageswap', async (e) => { if (isProfilePage(targetUrl)) { const profile = extractProfileNameFromUrl(targetUrl); - setTemporaryViewTransitionNames([ - [document.querySelector(`#${profile} span`), 'name'], - [document.querySelector(`#${profile} img`), 'avatar'], - ], e.viewTransition.finished); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#${profile} span`), "name"], + [document.querySelector(`#${profile} img`), "avatar"], + ], + e.viewTransition.finished, + ); } } }); From c894f7bba9ee93cd52df1c329c7658620c97cc5b Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:56:24 +0100 Subject: [PATCH 21/53] Update files/en-us/web/api/window/pageswap_event/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/window/pageswap_event/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index 52cdf710515d4bf..bcc4b09b6da8359 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -44,7 +44,9 @@ A {{domxref("PageSwapEvent")}}. Inherits from {{domxref("Event")}}. window.addEventListener('pageswap', async (e) => { // Only run this if an active view transition exists if (e.viewTransition) { - const currentUrl = e.activation.from?.url ? new URL(e.activation.from.url) : null; + const currentUrl = e.activation.from?.url + ? new URL(e.activation.from.url) + : null; const targetUrl = new URL(e.activation.entry.url); // Only transition to same basePath From a768586d32a7172d0b7871680779815d039e2eb3 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:57:26 +0100 Subject: [PATCH 22/53] Update files/en-us/web/api/pagerevealevent/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/pagerevealevent/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/index.md index afa1727fe308afa..5b687397db9de09 100644 --- a/files/en-us/web/api/pagerevealevent/index.md +++ b/files/en-us/web/api/pagerevealevent/index.md @@ -59,10 +59,13 @@ window.addEventListener('pagereveal', async (e) => { if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { const profile = extractProfileNameFromUrl(fromUrl); - setTemporaryViewTransitionNames([ - [document.querySelector(`#${profile} span`), 'name'], - [document.querySelector(`#${profile} img`), 'avatar'], - ], e.viewTransition.ready); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#${profile} span`), "name"], + [document.querySelector(`#${profile} img`), "avatar"], + ], + e.viewTransition.ready, + ); } // Went to profile page From d788f872c38d95d93cf0d0d7f69735b4606e7bd6 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:57:45 +0100 Subject: [PATCH 23/53] Update files/en-us/web/api/navigationactivation/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/navigationactivation/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/navigationactivation/index.md b/files/en-us/web/api/navigationactivation/index.md index c44910418201e42..10656690977f0ca 100644 --- a/files/en-us/web/api/navigationactivation/index.md +++ b/files/en-us/web/api/navigationactivation/index.md @@ -54,10 +54,13 @@ window.addEventListener("pagereveal", async (e) => { // Went to profile page // ~> Set VT names on the main title and image if (isProfilePage(currentUrl)) { - setTemporaryViewTransitionNames([ - [document.querySelector(`#detail main h1`), 'name'], - [document.querySelector(`#detail main img`), 'avatar'], - ], e.viewTransition.ready); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#detail main h1`), "name"], + [document.querySelector(`#detail main img`), "avatar"], + ], + e.viewTransition.ready, + ); } } }); From 03dccd379ea0abcf167b1ed8475860862058f17e Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:58:24 +0100 Subject: [PATCH 24/53] Update files/en-us/web/api/pagerevealevent/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/pagerevealevent/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/index.md index 5b687397db9de09..970af5495f55ca3 100644 --- a/files/en-us/web/api/pagerevealevent/index.md +++ b/files/en-us/web/api/pagerevealevent/index.md @@ -39,7 +39,7 @@ window.onpagehide = () => requestAnimationFrame(() => reveal()); ## Examples ```js -window.addEventListener('pagereveal', async (e) => { +window.addEventListener("pagereveal", async (e) => { // If the "from" history entry does not exist, return if (!navigation.activation.from) return; From 6ad60a1aad335d247483470904eb070955c5483c Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 15:59:17 +0100 Subject: [PATCH 25/53] Update files/en-us/web/api/window/pageswap_event/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/window/pageswap_event/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index bcc4b09b6da8359..ab4bc6e75ae3dcf 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -41,7 +41,7 @@ A {{domxref("PageSwapEvent")}}. Inherits from {{domxref("Event")}}. ## Examples ```js -window.addEventListener('pageswap', async (e) => { +window.addEventListener("pageswap", async (e) => { // Only run this if an active view transition exists if (e.viewTransition) { const currentUrl = e.activation.from?.url From 45fa3189b622dabc9ff6d697ea394f01f3d37be9 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:00:14 +0100 Subject: [PATCH 26/53] Update files/en-us/web/api/pagerevealevent/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/pagerevealevent/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/index.md index 970af5495f55ca3..7ffcf5466bfc927 100644 --- a/files/en-us/web/api/pagerevealevent/index.md +++ b/files/en-us/web/api/pagerevealevent/index.md @@ -71,10 +71,13 @@ window.addEventListener("pagereveal", async (e) => { // Went to profile page // ~> Set VT names on the main title and image if (isProfilePage(currentUrl)) { - setTemporaryViewTransitionNames([ - [document.querySelector(`#detail main h1`), 'name'], - [document.querySelector(`#detail main img`), 'avatar'], - ], e.viewTransition.ready); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#detail main h1`), "name"], + [document.querySelector(`#detail main img`), "avatar"], + ], + e.viewTransition.ready, + ); } } }); From be95206211522a9f256008efa4e4d2682b9f5e4e Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:00:52 +0100 Subject: [PATCH 27/53] Update files/en-us/web/api/navigationactivation/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/navigationactivation/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/navigationactivation/index.md b/files/en-us/web/api/navigationactivation/index.md index 10656690977f0ca..02197361761d2e6 100644 --- a/files/en-us/web/api/navigationactivation/index.md +++ b/files/en-us/web/api/navigationactivation/index.md @@ -45,10 +45,13 @@ window.addEventListener("pagereveal", async (e) => { if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { const profile = extractProfileNameFromUrl(fromUrl); - setTemporaryViewTransitionNames([ - [document.querySelector(`#${profile} span`), 'name'], - [document.querySelector(`#${profile} img`), 'avatar'], - ], e.viewTransition.ready); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#${profile} span`), "name"], + [document.querySelector(`#${profile} img`), "avatar"], + ], + e.viewTransition.ready, + ); } // Went to profile page From bb868a0449a920494dbffce8f6898c334d4247a0 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:01:48 +0100 Subject: [PATCH 28/53] Update files/en-us/web/api/pageswapevent/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/pageswapevent/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index 02f9fc1b555c587..6bbc08aa8546dcd 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -28,7 +28,7 @@ The pageswap event is fired when you navigate across documents, when the previou ## Examples ```js -window.addEventListener('pageswap', async (e) => { +window.addEventListener("pageswap", async (e) => { // Only run this if an active view transition exists if (e.viewTransition) { const currentUrl = e.activation.from?.url ? new URL(e.activation.from.url) : null; From 41911568944ec0ddced3036897d590cca09fd777 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:02:55 +0100 Subject: [PATCH 29/53] Update files/en-us/web/api/pageswapevent/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/pageswapevent/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index 6bbc08aa8546dcd..1e7a29a11ab1893 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -31,7 +31,9 @@ The pageswap event is fired when you navigate across documents, when the previou window.addEventListener("pageswap", async (e) => { // Only run this if an active view transition exists if (e.viewTransition) { - const currentUrl = e.activation.from?.url ? new URL(e.activation.from.url) : null; + const currentUrl = e.activation.from?.url + ? new URL(e.activation.from.url) + : null; const targetUrl = new URL(e.activation.entry.url); // Only transition to same basePath From 6faaebb4ddab373d1cbf73c98426ffb180791577 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:03:24 +0100 Subject: [PATCH 30/53] Update files/en-us/web/api/pageswapevent/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/pageswapevent/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index 1e7a29a11ab1893..aeb4390325d6fd2 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -45,10 +45,13 @@ window.addEventListener("pageswap", async (e) => { // Going from profile page to homepage // ~> The big img and title are the ones! if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { - setTemporaryViewTransitionNames([ - [document.querySelector(`#detail main h1`), 'name'], - [document.querySelector(`#detail main img`), 'avatar'], - ], e.viewTransition.finished); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#detail main h1`), "name"], + [document.querySelector(`#detail main img`), "avatar"], + ], + e.viewTransition.finished, + ); } // Going to profile page From d6d62ed22630b107eb6ac499b18900d043c6459d Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:04:09 +0100 Subject: [PATCH 31/53] Update files/en-us/web/api/pageswapevent/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/pageswapevent/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index aeb4390325d6fd2..fccec9281b8ecb9 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -59,10 +59,13 @@ window.addEventListener("pageswap", async (e) => { if (isProfilePage(targetUrl)) { const profile = extractProfileNameFromUrl(targetUrl); - setTemporaryViewTransitionNames([ - [document.querySelector(`#${profile} span`), 'name'], - [document.querySelector(`#${profile} img`), 'avatar'], - ], e.viewTransition.finished); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#${profile} span`), "name"], + [document.querySelector(`#${profile} img`), "avatar"], + ], + e.viewTransition.finished, + ); } } }); From c4ef9cc9aa5e7434cefbc050c458d23ad9d24376 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:04:55 +0100 Subject: [PATCH 32/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/view_transitions_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 5656204f368aa16..1e8389e7077113d 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -359,7 +359,7 @@ The [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/p The {{domxref("Window.pageswap_event", "pageswap")}} event listener looks as follows. This sets view transition names on the elements on the outbound page that link to the profile pages. When navigating from the home page to a profile page, custom animations are provided _only_ for the linked element that is clicked in each case. ```js -window.addEventListener('pageswap', async (e) => { +window.addEventListener("pageswap", async (e) => { // Only run this if an active view transition exists if (e.viewTransition) { const currentUrl = e.activation.from?.url ? new URL(e.activation.from.url) : null; From 781ad757ea283fb2703d12b0478cee6f7d5f0aa3 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:06:50 +0100 Subject: [PATCH 33/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/view_transitions_api/using/index.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 1e8389e7077113d..a15d72e7f97d98a 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -362,7 +362,9 @@ The {{domxref("Window.pageswap_event", "pageswap")}} event listener looks as fol window.addEventListener("pageswap", async (e) => { // Only run this if an active view transition exists if (e.viewTransition) { - const currentUrl = e.activation.from?.url ? new URL(e.activation.from.url) : null; + const currentUrl = e.activation.from?.url + ? new URL(e.activation.from.url) + : null; const targetUrl = new URL(e.activation.entry.url); // Only transition to same basePath From 220f1385665b3ed71b9bedc2fc1709627a10137d Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:08:12 +0100 Subject: [PATCH 34/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../en-us/web/api/view_transitions_api/using/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index a15d72e7f97d98a..5a6a75e443a9880 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -376,10 +376,13 @@ window.addEventListener("pageswap", async (e) => { // Going from profile page to homepage // ~> The big img and title are the ones! if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { - setTemporaryViewTransitionNames([ - [document.querySelector(`#detail main h1`), 'name'], - [document.querySelector(`#detail main img`), 'avatar'], - ], e.viewTransition.finished); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#detail main h1`), "name"], + [document.querySelector(`#detail main img`), "avatar"], + ], + e.viewTransition.finished, + ); } // Going to profile page From fdd0cd2432bd590cec6ed771685d4fb824946f14 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:09:56 +0100 Subject: [PATCH 35/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../en-us/web/api/view_transitions_api/using/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 5a6a75e443a9880..b9f963454ec7c39 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -390,10 +390,13 @@ window.addEventListener("pageswap", async (e) => { if (isProfilePage(targetUrl)) { const profile = extractProfileNameFromUrl(targetUrl); - setTemporaryViewTransitionNames([ - [document.querySelector(`#${profile} span`), 'name'], - [document.querySelector(`#${profile} img`), 'avatar'], - ], e.viewTransition.finished); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#${profile} span`), "name"], + [document.querySelector(`#${profile} img`), "avatar"], + ], + e.viewTransition.finished, + ); } } }); From d557f5ca98135b61c541db4009738ede6ea453e6 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:10:38 +0100 Subject: [PATCH 36/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/view_transitions_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index b9f963454ec7c39..36f50529260a153 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -405,7 +405,7 @@ window.addEventListener("pageswap", async (e) => { The {{domxref("Window.pagereveal_event", "pagereveal")}} event listener looks as follows. This works in a similar way to the `pageswap` event listener, although bear in mind that here we are customizing the "to" animation, for page elements on the new page. ```js -window.addEventListener('pagereveal', async (e) => { +window.addEventListener("pagereveal", async (e) => { // If the "from" history entry does not exist, return if (!navigation.activation.from) return; From ecdc3d3e8c39df05d4a0a353fc57346ef9234334 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:11:17 +0100 Subject: [PATCH 37/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../en-us/web/api/view_transitions_api/using/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 36f50529260a153..718f6a29c70c8ab 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -425,10 +425,13 @@ window.addEventListener("pagereveal", async (e) => { if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { const profile = extractProfileNameFromUrl(fromUrl); - setTemporaryViewTransitionNames([ - [document.querySelector(`#${profile} span`), 'name'], - [document.querySelector(`#${profile} img`), 'avatar'], - ], e.viewTransition.ready); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#${profile} span`), "name"], + [document.querySelector(`#${profile} img`), "avatar"], + ], + e.viewTransition.ready, + ); } // Went to profile page From c7fa835bc4d980f4a54708a2ca29ca8d4ef8ac93 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:11:58 +0100 Subject: [PATCH 38/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../en-us/web/api/view_transitions_api/using/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 718f6a29c70c8ab..9d6355249d9c775 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -437,10 +437,13 @@ window.addEventListener("pagereveal", async (e) => { // Went to profile page // ~> Set VT names on the main title and image if (isProfilePage(currentUrl)) { - setTemporaryViewTransitionNames([ - [document.querySelector(`#detail main h1`), 'name'], - [document.querySelector(`#detail main img`), 'avatar'], - ], e.viewTransition.ready); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#detail main h1`), "name"], + [document.querySelector(`#detail main img`), "avatar"], + ], + e.viewTransition.ready, + ); } } }); From c203f384571b134345c207e45b2ab08d28e14d8a Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:13:39 +0100 Subject: [PATCH 39/53] Update files/en-us/web/api/window/pagereveal_event/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/window/pagereveal_event/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/window/pagereveal_event/index.md b/files/en-us/web/api/window/pagereveal_event/index.md index ff53dc683bb34b1..de1b2d920816e37 100644 --- a/files/en-us/web/api/window/pagereveal_event/index.md +++ b/files/en-us/web/api/window/pagereveal_event/index.md @@ -66,10 +66,13 @@ window.addEventListener('pagereveal', async (e) => { // Went to profile page // ~> Set VT names on the main title and image if (isProfilePage(currentUrl)) { - setTemporaryViewTransitionNames([ - [document.querySelector(`#detail main h1`), 'name'], - [document.querySelector(`#detail main img`), 'avatar'], - ], e.viewTransition.ready); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#detail main h1`), "name"], + [document.querySelector(`#detail main img`), "avatar"], + ], + e.viewTransition.ready, + ); } } }); From 3022d227c2c78e2da515bd48c64c3608d88354d0 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:14:45 +0100 Subject: [PATCH 40/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/view_transitions_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 9d6355249d9c775..1d75b77477ec671 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -461,7 +461,7 @@ const setTemporaryViewTransitionNames = async (entries, vtPromise) => { // Await the view transition promise passed into the function, e.g. ready or finished await vtPromise; - // Remove the custom view transition from each element passed into the function + // Remove the custom view transition from each element passed into the function for (const [$el, name] of entries) { $el.style.viewTransitionName = ''; } From f757a6422608c78ed53d8bdfa29797afdb416525 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:16:32 +0100 Subject: [PATCH 41/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/view_transitions_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 1d75b77477ec671..5e2cbbd031b9a74 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -463,7 +463,7 @@ const setTemporaryViewTransitionNames = async (entries, vtPromise) => { // Remove the custom view transition from each element passed into the function for (const [$el, name] of entries) { - $el.style.viewTransitionName = ''; + $el.style.viewTransitionName = ""; } } ``` From 1d2e5d3b24a8259c85cc2b5385ff905043d49c44 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:18:38 +0100 Subject: [PATCH 42/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/view_transitions_api/using/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 5e2cbbd031b9a74..c4d40ed0fde4be4 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -465,7 +465,7 @@ const setTemporaryViewTransitionNames = async (entries, vtPromise) => { for (const [$el, name] of entries) { $el.style.viewTransitionName = ""; } -} +}; ``` ## Stabilizing page state to make cross-document transitions consistent From 7f84898e7f42b95181499d5d6557c1d9d789ae9e Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:19:32 +0100 Subject: [PATCH 43/53] Update files/en-us/web/api/window/pagereveal_event/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/window/pagereveal_event/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/window/pagereveal_event/index.md b/files/en-us/web/api/window/pagereveal_event/index.md index de1b2d920816e37..341f6dbd2791eb4 100644 --- a/files/en-us/web/api/window/pagereveal_event/index.md +++ b/files/en-us/web/api/window/pagereveal_event/index.md @@ -37,7 +37,7 @@ A {{domxref("PageRevealEvent")}}. Inherits from {{domxref("Event")}}. ## Examples ```js -window.addEventListener('pagereveal', async (e) => { +window.addEventListener("pagereveal", async (e) => { // If the "from" history entry does not exist, return if (!navigation.activation.from) return; From c97f06182681fa5b596f247505dd2f297869856f Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 24 May 2024 16:20:08 +0100 Subject: [PATCH 44/53] Update files/en-us/web/api/window/pagereveal_event/index.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- files/en-us/web/api/window/pagereveal_event/index.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/files/en-us/web/api/window/pagereveal_event/index.md b/files/en-us/web/api/window/pagereveal_event/index.md index 341f6dbd2791eb4..d16102408639e4a 100644 --- a/files/en-us/web/api/window/pagereveal_event/index.md +++ b/files/en-us/web/api/window/pagereveal_event/index.md @@ -57,10 +57,13 @@ window.addEventListener("pagereveal", async (e) => { if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { const profile = extractProfileNameFromUrl(fromUrl); - setTemporaryViewTransitionNames([ - [document.querySelector(`#${profile} span`), 'name'], - [document.querySelector(`#${profile} img`), 'avatar'], - ], e.viewTransition.ready); + setTemporaryViewTransitionNames( + [ + [document.querySelector(`#${profile} span`), "name"], + [document.querySelector(`#${profile} img`), "avatar"], + ], + e.viewTransition.ready, + ); } // Went to profile page From 64b2e7e206b71d3fb4318f44e35d81951ea0ef67 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 12 Jun 2024 19:04:49 +0100 Subject: [PATCH 45/53] Fixes for bramus tech review comments --- .../web/api/navigationactivation/index.md | 51 ++++---- files/en-us/web/api/pagerevealevent/index.md | 46 ++++--- files/en-us/web/api/pageswapevent/index.md | 46 ++++--- .../web/api/view_transitions_api/index.md | 2 +- .../api/view_transitions_api/using/index.md | 115 ++++++++---------- .../viewtransition/skiptransition/index.md | 4 +- .../web/api/window/pagereveal_event/index.md | 46 ++++--- .../web/api/window/pageswap_event/index.md | 46 ++++--- 8 files changed, 191 insertions(+), 165 deletions(-) diff --git a/files/en-us/web/api/navigationactivation/index.md b/files/en-us/web/api/navigationactivation/index.md index 02197361761d2e6..ce6fd9b07073157 100644 --- a/files/en-us/web/api/navigationactivation/index.md +++ b/files/en-us/web/api/navigationactivation/index.md @@ -11,7 +11,10 @@ browser-compat: api.NavigationActivation The **`NavigationActivation`** interface of the [Navigation API](/en-US/docs/Web/API/Navigation_API) represents a recent cross-document navigation. It contains the navigation type and outgoing and inbound document history entries. -This object is accessed via the {{domxref("PageSwapEvent.activation")}} and {{domxref("Navigation.activation")}} properties. +This object is accessed via the {{domxref("PageSwapEvent.activation")}} and {{domxref("Navigation.activation")}} properties. Note that, in each case, the `NavigationActivation` represents a different navigation: + +- `Navigation.activation` represents information about the navigation to the current page. +- `PageSwapEvent.activation` represents information about the navigation to the next page. ## Instance properties @@ -34,36 +37,42 @@ window.addEventListener("pagereveal", async (e) => { const fromUrl = new URL(navigation.activation.from.url); const currentUrl = new URL(navigation.activation.entry.url); - // Only transition to/from same basePath - // ~> SKIP! - if (!fromUrl.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Went from profile page to homepage // ~> Set VT names on the relevant list item if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { const profile = extractProfileNameFromUrl(fromUrl); - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#${profile} span`), "name"], - [document.querySelector(`#${profile} img`), "avatar"], - ], - e.viewTransition.ready, - ); + // Set view-transition-name values on the elements to animate + 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"; } // Went to profile page // ~> Set VT names on the main title and image if (isProfilePage(currentUrl)) { - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#detail main h1`), "name"], - [document.querySelector(`#detail main img`), "avatar"], - ], - e.viewTransition.ready, - ); + // Set view-transition-name values on the elements to animate + document.querySelector(`#detail main h1`).style.viewTransitionName = + "name"; + document.querySelector(`#detail main 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(`#detail main h1`).style.viewTransitionName = + "none"; + document.querySelector(`#detail main img`).style.viewTransitionName = + "none"; } } }); diff --git a/files/en-us/web/api/pagerevealevent/index.md b/files/en-us/web/api/pagerevealevent/index.md index 7ffcf5466bfc927..655646b72508531 100644 --- a/files/en-us/web/api/pagerevealevent/index.md +++ b/files/en-us/web/api/pagerevealevent/index.md @@ -48,36 +48,42 @@ window.addEventListener("pagereveal", async (e) => { const fromUrl = new URL(navigation.activation.from.url); const currentUrl = new URL(navigation.activation.entry.url); - // Only transition to/from same basePath - // ~> SKIP! - if (!fromUrl.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Went from profile page to homepage // ~> Set VT names on the relevant list item if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { const profile = extractProfileNameFromUrl(fromUrl); - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#${profile} span`), "name"], - [document.querySelector(`#${profile} img`), "avatar"], - ], - e.viewTransition.ready, - ); + // Set view-transition-name values on the elements to animate + 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"; } // Went to profile page // ~> Set VT names on the main title and image if (isProfilePage(currentUrl)) { - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#detail main h1`), "name"], - [document.querySelector(`#detail main img`), "avatar"], - ], - e.viewTransition.ready, - ); + // Set view-transition-name values on the elements to animate + document.querySelector(`#detail main h1`).style.viewTransitionName = + "name"; + document.querySelector(`#detail main 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(`#detail main h1`).style.viewTransitionName = + "none"; + document.querySelector(`#detail main img`).style.viewTransitionName = + "none"; } } }); diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index fccec9281b8ecb9..0ce174ba1a04fa0 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -36,22 +36,22 @@ window.addEventListener("pageswap", async (e) => { : null; const targetUrl = new URL(e.activation.entry.url); - // Only transition to same basePath - // ~> SKIP! - if (!targetUrl.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Going from profile page to homepage // ~> The big img and title are the ones! if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#detail main h1`), "name"], - [document.querySelector(`#detail main img`), "avatar"], - ], - e.viewTransition.finished, - ); + // Set view-transition-name values on the elements to animate + document.querySelector(`#detail main h1`).style.viewTransitionName = + "name"; + document.querySelector(`#detail main 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(`#detail main h1`).style.viewTransitionName = + "none"; + document.querySelector(`#detail main img`).style.viewTransitionName = + "none"; } // Going to profile page @@ -59,13 +59,19 @@ window.addEventListener("pageswap", async (e) => { if (isProfilePage(targetUrl)) { const profile = extractProfileNameFromUrl(targetUrl); - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#${profile} span`), "name"], - [document.querySelector(`#${profile} img`), "avatar"], - ], - e.viewTransition.finished, - ); + // Set view-transition-name values on the elements to animate + 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"; } } }); diff --git a/files/en-us/web/api/view_transitions_api/index.md b/files/en-us/web/api/view_transitions_api/index.md index aa804b83ab7174d..881bc23db331a11 100644 --- a/files/en-us/web/api/view_transitions_api/index.md +++ b/files/en-us/web/api/view_transitions_api/index.md @@ -6,7 +6,7 @@ status: - experimental browser-compat: - api.Document.startViewTransition - - api.ViewTransition + - css.at-rules.view-transition spec-urls: https://drafts.csswg.org/css-view-transitions/ --- diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index c4d40ed0fde4be4..eb6be6fe84c2998 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -49,14 +49,14 @@ To handle creating the outbound and inbound transition animations, the API const └─ ::view-transition-new(root) ``` -> **Note:** a {{cssxref("::view-transition-group")}} is created for every view-transition-name that was captured? +> **Note:** a {{cssxref("::view-transition-group")}} subtree is created for every captured `view-transition-name`. In the case of same-document transitions (SPAs), the pseudo-element tree is made available in the document. In the case of cross-document transitions (MPAs), the pseudo-element tree is made available in the destination document only. The most interesting parts of the tree structure are as follows: - {{cssxref("::view-transition")}} is the root of view transitions overlay, which contains all view transition snapshot groups and sits over the top of all other page content. -- A {{cssxref("::view-transition-group")}} acts as a container for each view transition snapshot group. The `root` argument specifies the default snapshot group — the view transition animation will apply to the `:root` element and all elements nested within it. +- A {{cssxref("::view-transition-group")}} acts as a container for each view transition snapshot group. The `root` argument specifies the default snapshot group — the view transition animation will apply to the snapshot whose `view-transition-name` is `root`. > **Note:** It is possible to target different DOM elements with different custom view transition animations by setting a different {{cssxref("view-transition-name")}} on each one. In such cases, a `::view-transition-group` is created for each one. See [Different animations for different elements](#different_animations_for_different_elements) for an example. - {{cssxref("::view-transition-old")}} targets the static snapshot of the old page element, and {{cssxref("::view-transition-new")}} targets the live snapshot of the new page element. Both of these render as replaced content, in the same manner as an {{htmlelement("img")}} or {{htmlelement("video")}}, meaning that they can be styled with handy properties like {{cssxref("object-fit")}} and {{cssxref("object-position")}}. @@ -367,22 +367,22 @@ window.addEventListener("pageswap", async (e) => { : null; const targetUrl = new URL(e.activation.entry.url); - // Only transition to same basePath - // ~> SKIP! - if (!targetUrl.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Going from profile page to homepage // ~> The big img and title are the ones! if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#detail main h1`), "name"], - [document.querySelector(`#detail main img`), "avatar"], - ], - e.viewTransition.finished, - ); + // Set view-transition-name values on the elements to animate + document.querySelector(`#detail main h1`).style.viewTransitionName = + "name"; + document.querySelector(`#detail main 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(`#detail main h1`).style.viewTransitionName = + "none"; + document.querySelector(`#detail main img`).style.viewTransitionName = + "none"; } // Going to profile page @@ -390,13 +390,19 @@ window.addEventListener("pageswap", async (e) => { if (isProfilePage(targetUrl)) { const profile = extractProfileNameFromUrl(targetUrl); - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#${profile} span`), "name"], - [document.querySelector(`#${profile} img`), "avatar"], - ], - e.viewTransition.finished, - ); + // Set view-transition-name values on the elements to animate + 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"; } } }); @@ -414,60 +420,47 @@ window.addEventListener("pagereveal", async (e) => { const fromUrl = new URL(navigation.activation.from.url); const currentUrl = new URL(navigation.activation.entry.url); - // Only transition to/from same basePath - // ~> SKIP! - if (!fromUrl.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Went from profile page to homepage // ~> Set VT names on the relevant list item if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { const profile = extractProfileNameFromUrl(fromUrl); - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#${profile} span`), "name"], - [document.querySelector(`#${profile} img`), "avatar"], - ], - e.viewTransition.ready, - ); + // Set view-transition-name values on the elements to animate + 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"; } // Went to profile page // ~> Set VT names on the main title and image if (isProfilePage(currentUrl)) { - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#detail main h1`), "name"], - [document.querySelector(`#detail main img`), "avatar"], - ], - e.viewTransition.ready, - ); + // Set view-transition-name values on the elements to animate + document.querySelector(`#detail main h1`).style.viewTransitionName = + "name"; + document.querySelector(`#detail main 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(`#detail main h1`).style.viewTransitionName = + "none"; + document.querySelector(`#detail main img`).style.viewTransitionName = + "none"; } } }); ``` -The `setTemporaryViewTransitionNames()` user-defined function is used repeatedly in this code. This looks like so: - -```js -const setTemporaryViewTransitionNames = async (entries, vtPromise) => { - // Apply a custom view transition to each element passed into the function - for (const [$el, name] of entries) { - $el.style.viewTransitionName = name; - } - - // Await the view transition promise passed into the function, e.g. ready or finished - await vtPromise; - - // Remove the custom view transition from each element passed into the function - for (const [$el, name] of entries) { - $el.style.viewTransitionName = ""; - } -}; -``` - ## Stabilizing page state to make cross-document transitions consistent Before running a cross-document transition, you ideally want to wait until the state of the page stabilizes, relying on [render blocking](/en-US/docs/Glossary/Render_blocking) to ensure that: diff --git a/files/en-us/web/api/viewtransition/skiptransition/index.md b/files/en-us/web/api/viewtransition/skiptransition/index.md index 70b73126ffbe371..387f973c96363b7 100644 --- a/files/en-us/web/api/viewtransition/skiptransition/index.md +++ b/files/en-us/web/api/viewtransition/skiptransition/index.md @@ -44,12 +44,12 @@ transition.skipTransition(); ```js // Fired on the current (outgoing) page document.addEventListener("pageswap", (event) => { - event.viewTransition.skipTransition(); + event.viewTransition?.skipTransition(); }); // Fired on the destination (inbound) page document.addEventListener("pagereveal", (event) => { - event.viewTransition.skipTransition(); + event.viewTransition?.skipTransition(); }); ``` diff --git a/files/en-us/web/api/window/pagereveal_event/index.md b/files/en-us/web/api/window/pagereveal_event/index.md index d16102408639e4a..3be4e0d171a5d5f 100644 --- a/files/en-us/web/api/window/pagereveal_event/index.md +++ b/files/en-us/web/api/window/pagereveal_event/index.md @@ -46,36 +46,42 @@ window.addEventListener("pagereveal", async (e) => { const fromUrl = new URL(navigation.activation.from.url); const currentUrl = new URL(navigation.activation.entry.url); - // Only transition to/from same basePath - // ~> SKIP! - if (!fromUrl.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Went from profile page to homepage // ~> Set VT names on the relevant list item if (isProfilePage(fromUrl) && isHomePage(currentUrl)) { const profile = extractProfileNameFromUrl(fromUrl); - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#${profile} span`), "name"], - [document.querySelector(`#${profile} img`), "avatar"], - ], - e.viewTransition.ready, - ); + // Set view-transition-name values on the elements to animate + 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"; } // Went to profile page // ~> Set VT names on the main title and image if (isProfilePage(currentUrl)) { - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#detail main h1`), "name"], - [document.querySelector(`#detail main img`), "avatar"], - ], - e.viewTransition.ready, - ); + // Set view-transition-name values on the elements to animate + document.querySelector(`#detail main h1`).style.viewTransitionName = + "name"; + document.querySelector(`#detail main 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(`#detail main h1`).style.viewTransitionName = + "none"; + document.querySelector(`#detail main img`).style.viewTransitionName = + "none"; } } }); diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index ab4bc6e75ae3dcf..9ab2759e9d37408 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -49,22 +49,22 @@ window.addEventListener("pageswap", async (e) => { : null; const targetUrl = new URL(e.activation.entry.url); - // Only transition to same basePath - // ~> SKIP! - if (!targetUrl.pathname.startsWith(basePath)) { - e.viewTransition.skipTransition(); - } - // Going from profile page to homepage // ~> The big img and title are the ones! if (isProfilePage(currentUrl) && isHomePage(targetUrl)) { - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#detail main h1`), "name"], - [document.querySelector(`#detail main img`), "avatar"], - ], - e.viewTransition.finished, - ); + // Set view-transition-name values on the elements to animate + document.querySelector(`#detail main h1`).style.viewTransitionName = + "name"; + document.querySelector(`#detail main 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(`#detail main h1`).style.viewTransitionName = + "none"; + document.querySelector(`#detail main img`).style.viewTransitionName = + "none"; } // Going to profile page @@ -72,13 +72,19 @@ window.addEventListener("pageswap", async (e) => { if (isProfilePage(targetUrl)) { const profile = extractProfileNameFromUrl(targetUrl); - setTemporaryViewTransitionNames( - [ - [document.querySelector(`#${profile} span`), "name"], - [document.querySelector(`#${profile} img`), "avatar"], - ], - e.viewTransition.finished, - ); + // Set view-transition-name values on the elements to animate + 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"; } } }); From 0aef236377aa4996a47cc6c21c6fb522e589d48f Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 13 Jun 2024 11:51:49 +0100 Subject: [PATCH 46/53] Update files/en-us/web/api/pageswapevent/index.md Co-authored-by: Bramus --- files/en-us/web/api/pageswapevent/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index 0ce174ba1a04fa0..5310431ca56e619 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -45,9 +45,9 @@ window.addEventListener("pageswap", async (e) => { document.querySelector(`#detail main img`).style.viewTransitionName = "avatar"; - // Remove names after snapshots have been taken - // so that we're ready for the next navigation - await e.viewTransition.ready; + // Remove view-transition-names after snapshots have been taken + // (this to deal with BFCache) + await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; document.querySelector(`#detail main img`).style.viewTransitionName = From 34fadad959b865537a54d67e0293636295fa47ee Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 13 Jun 2024 11:52:03 +0100 Subject: [PATCH 47/53] Update files/en-us/web/api/pageswapevent/index.md Co-authored-by: Bramus --- files/en-us/web/api/pageswapevent/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index 5310431ca56e619..8d00b90c18e83fb 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -65,9 +65,9 @@ window.addEventListener("pageswap", async (e) => { 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; + // 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 = From afcc4310924b88c6be1d49a2ba4d2adb9d38cf9a Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 13 Jun 2024 11:52:17 +0100 Subject: [PATCH 48/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: Bramus --- files/en-us/web/api/view_transitions_api/using/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index eb6be6fe84c2998..21ef9ad8ee025a1 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -376,9 +376,9 @@ window.addEventListener("pageswap", async (e) => { document.querySelector(`#detail main img`).style.viewTransitionName = "avatar"; - // Remove names after snapshots have been taken - // so that we're ready for the next navigation - await e.viewTransition.ready; + // Remove view-transition-names after snapshots have been taken + // (this to deal with BFCache) + await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; document.querySelector(`#detail main img`).style.viewTransitionName = From 4913b12646cc2f95ca0d7c1e312ec77cc891a8a4 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 13 Jun 2024 11:52:34 +0100 Subject: [PATCH 49/53] Update files/en-us/web/api/view_transitions_api/using/index.md Co-authored-by: Bramus --- files/en-us/web/api/view_transitions_api/using/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 21ef9ad8ee025a1..cb69dd5b1bd1fe8 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -396,9 +396,9 @@ window.addEventListener("pageswap", async (e) => { 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; + // 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 = From cc29537a012bbf27183719f36cef59bdb32e2eec Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 13 Jun 2024 11:52:46 +0100 Subject: [PATCH 50/53] Update files/en-us/web/api/window/pageswap_event/index.md Co-authored-by: Bramus --- files/en-us/web/api/window/pageswap_event/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index 9ab2759e9d37408..39e93f8dd8ae0d2 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -58,9 +58,9 @@ window.addEventListener("pageswap", async (e) => { document.querySelector(`#detail main img`).style.viewTransitionName = "avatar"; - // Remove names after snapshots have been taken - // so that we're ready for the next navigation - await e.viewTransition.ready; + // Remove view-transition-names after snapshots have been taken + // (this to deal with BFCache) + await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; document.querySelector(`#detail main img`).style.viewTransitionName = From e3ead76601dd42a5547e27f0a3fe29f03720fc97 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 13 Jun 2024 11:53:03 +0100 Subject: [PATCH 51/53] Update files/en-us/web/api/window/pageswap_event/index.md Co-authored-by: Bramus --- files/en-us/web/api/window/pageswap_event/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index 39e93f8dd8ae0d2..36b2c1138a3858e 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -78,9 +78,9 @@ window.addEventListener("pageswap", async (e) => { 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; + // 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 = From 6fff8112a1ab9b7be8c8f83e0fcf611ef5877b2d Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 13 Jun 2024 12:24:36 +0100 Subject: [PATCH 52/53] A few more fixes --- files/en-us/web/api/pageswapevent/index.md | 4 ++-- .../api/view_transitions_api/using/index.md | 18 ++++++++++++++---- .../web/api/window/pageswap_event/index.md | 4 ++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index 8d00b90c18e83fb..902af5e19461607 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -46,7 +46,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this to deal with BFCache) + // (this is to deal with BFCache) await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; @@ -66,7 +66,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this to deal with BFCache) + // (this is to deal with BFCache) await e.viewTransition.finished; document.querySelector(`#${profile} span`).style.viewTransitionName = "none"; diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index cb69dd5b1bd1fe8..3b5c20041bd40ef 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -56,10 +56,20 @@ In the case of same-document transitions (SPAs), the pseudo-element tree is made The most interesting parts of the tree structure are as follows: - {{cssxref("::view-transition")}} is the root of view transitions overlay, which contains all view transition snapshot groups and sits over the top of all other page content. -- A {{cssxref("::view-transition-group")}} acts as a container for each view transition snapshot group. The `root` argument specifies the default snapshot group — the view transition animation will apply to the snapshot whose `view-transition-name` is `root`. - > **Note:** It is possible to target different DOM elements with different custom view transition animations by setting a different {{cssxref("view-transition-name")}} on each one. In such cases, a `::view-transition-group` is created for each one. See [Different animations for different elements](#different_animations_for_different_elements) for an example. +- A {{cssxref("::view-transition-group")}} acts as a container for each view transition snapshot group. The `root` argument specifies the default snapshot group — the view transition animation will apply to the snapshot whose `view-transition-name` is `root`. By default, this is the {{cssxref(":root")}} element, because the default browser styles define this: + + ```css + :root { + view-transition-name: root; + } + ``` + + Be aware however that page authors can change this by unsetting the above, and setting `view-transition-name: root` on a different element. + - {{cssxref("::view-transition-old")}} targets the static snapshot of the old page element, and {{cssxref("::view-transition-new")}} targets the live snapshot of the new page element. Both of these render as replaced content, in the same manner as an {{htmlelement("img")}} or {{htmlelement("video")}}, meaning that they can be styled with handy properties like {{cssxref("object-fit")}} and {{cssxref("object-position")}}. +> **Note:** It is possible to target different DOM elements with different custom view transition animations by setting a different {{cssxref("view-transition-name")}} on each one. In such cases, a `::view-transition-group` is created for each one. See [Different animations for different elements](#different_animations_for_different_elements) for an example. + > **Note:** As you'll see later, to customize the outbound and inbound animations you need to target the {{cssxref("::view-transition-old")}} and {{cssxref("::view-transition-new")}} pseudo-elements with your animations, respectively. ## Creating a basic view transition @@ -377,7 +387,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this to deal with BFCache) + // (this is to deal with BFCache) await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; @@ -397,7 +407,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this to deal with BFCache) + // (this is to deal with BFCache) await e.viewTransition.finished; document.querySelector(`#${profile} span`).style.viewTransitionName = "none"; diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index 36b2c1138a3858e..2034b1acc6afdc4 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -59,7 +59,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this to deal with BFCache) + // (this is to deal with BFCache) await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; @@ -79,7 +79,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this to deal with BFCache) + // (this is to deal with BFCache) await e.viewTransition.finished; document.querySelector(`#${profile} span`).style.viewTransitionName = "none"; From aec4da834ba71a7c2a11d292e12275868a379b48 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 13 Jun 2024 15:40:17 +0100 Subject: [PATCH 53/53] Clarify bfcache notes and add explanation about bfcache conflict issue --- files/en-us/web/api/pageswapevent/index.md | 4 ++-- .../en-us/web/api/view_transitions_api/using/index.md | 10 ++++++---- files/en-us/web/api/window/pageswap_event/index.md | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/files/en-us/web/api/pageswapevent/index.md b/files/en-us/web/api/pageswapevent/index.md index 902af5e19461607..1a2b48ae6a52cfb 100644 --- a/files/en-us/web/api/pageswapevent/index.md +++ b/files/en-us/web/api/pageswapevent/index.md @@ -46,7 +46,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this is to deal with BFCache) + // Stops naming conflicts resulting from the page state persisting in BFCache await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; @@ -66,7 +66,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this is to deal with BFCache) + // Stops naming conflicts resulting from the page state persisting in BFCache await e.viewTransition.finished; document.querySelector(`#${profile} span`).style.viewTransitionName = "none"; diff --git a/files/en-us/web/api/view_transitions_api/using/index.md b/files/en-us/web/api/view_transitions_api/using/index.md index 3b5c20041bd40ef..3c8d5f43cffba37 100644 --- a/files/en-us/web/api/view_transitions_api/using/index.md +++ b/files/en-us/web/api/view_transitions_api/using/index.md @@ -292,7 +292,7 @@ The `ViewTransition` can be accessed like so: - A {{domxref("Window.pageswap_event", "pageswap")}} event is fired when a document is about to be unloaded due to a navigation. Its event object ({{domxref("PageSwapEvent")}}) provides access to the `ViewTransition` via the {{domxref("PageSwapEvent.viewTransition")}} property, as well as a {{domxref("NavigationActivation")}} via {{domxref("PageSwapEvent.activation")}} containing the navigation type and current and destination document history entries. > **Note:** If the navigation has a cross-origin URL anywhere in the redirect chain, the `activation` property returns `null`. -- A {{domxref("Window.pagereveal_event", "pagereveal")}} event is fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](https://web.dev/articles/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). Its event object ({{domxref("PageRevealEvent")}}) provides access to the `ViewTransition` via the {{domxref("PageRevealEvent.viewTransition")}} property. +- A {{domxref("Window.pagereveal_event", "pagereveal")}} event is fired when a document is first rendered, either when loading a fresh document from the network or activating a document (either from [bfcache](/en-US/docs/Glossary/bfcache) or [prerender](/en-US/docs/Glossary/Prerender)). Its event object ({{domxref("PageRevealEvent")}}) provides access to the `ViewTransition` via the {{domxref("PageRevealEvent.viewTransition")}} property. Let's have a look at some example code to show how these features could be used. @@ -364,7 +364,7 @@ This animation also requires the following CSS, to turn off the default CSS anim ### A JavaScript-powered custom cross-document (MPA) transition -The [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) demo provides a basic set of team profile pages, and demonstrates how to use the {{domxref("Window.pagereveal_event", "pagereveal")}} and {{domxref("Window.pageswap_event", "pageswap")}} events to customize the outgoing and inbound animations of a cross-document view transition based on the "from" and "to" URLs. +The [List of Chrome Dev Rel team members](https://view-transitions.netlify.app/profiles/mpa/) demo provides a basic set of team profile pages, and demonstrates how to use the {{domxref("Window.pageswap_event", "pageswap")}} and {{domxref("Window.pagereveal_event", "pagereveal")}} events to customize the outgoing and inbound animations of a cross-document view transition based on the "from" and "to" URLs. The {{domxref("Window.pageswap_event", "pageswap")}} event listener looks as follows. This sets view transition names on the elements on the outbound page that link to the profile pages. When navigating from the home page to a profile page, custom animations are provided _only_ for the linked element that is clicked in each case. @@ -387,7 +387,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this is to deal with BFCache) + // Stops naming conflicts resulting from the page state persisting in BFCache await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; @@ -407,7 +407,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this is to deal with BFCache) + // Stops naming conflicts resulting from the page state persisting in BFCache await e.viewTransition.finished; document.querySelector(`#${profile} span`).style.viewTransitionName = "none"; @@ -418,6 +418,8 @@ window.addEventListener("pageswap", async (e) => { }); ``` +> **Note:** We remove the `view-transition-name` values after snapshots have been taken in each case. If we left them set, they would persist in the page state saved in the [bfcache](/en-US/docs/Glossary/bfcache) upon navigation. If the back button was then pressed, the `pagereveal` event handler of the page being navigated back to would then attempt to set the same `view-transition-name` values on different elements. If multiple elements have the same `view-transition-name` set, the view transition is skipped. + The {{domxref("Window.pagereveal_event", "pagereveal")}} event listener looks as follows. This works in a similar way to the `pageswap` event listener, although bear in mind that here we are customizing the "to" animation, for page elements on the new page. ```js diff --git a/files/en-us/web/api/window/pageswap_event/index.md b/files/en-us/web/api/window/pageswap_event/index.md index 2034b1acc6afdc4..bb4539e235c936a 100644 --- a/files/en-us/web/api/window/pageswap_event/index.md +++ b/files/en-us/web/api/window/pageswap_event/index.md @@ -59,7 +59,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this is to deal with BFCache) + // Stops naming conflicts resulting from the page state persisting in BFCache await e.viewTransition.finished; document.querySelector(`#detail main h1`).style.viewTransitionName = "none"; @@ -79,7 +79,7 @@ window.addEventListener("pageswap", async (e) => { "avatar"; // Remove view-transition-names after snapshots have been taken - // (this is to deal with BFCache) + // Stops naming conflicts resulting from the page state persisting in BFCache await e.viewTransition.finished; document.querySelector(`#${profile} span`).style.viewTransitionName = "none";