This section is non-normative.
View Transitions, as specified in [css-view-transitions-1], is a feature that allows developers to create animated transitions between visual states of the document.
Level 2 extends that specification, by adding the necessary API and lifecycle to enable transitions across a same-origin cross-document navigation, as well as a few additions that make it easier to author pages with richer view transitions.
Level 2 defines the following:
Cross-document view transitions, including the @view-transition rule and the algorithms that enable the cross-document view transition lifecycle.
Selective view transitions, a way to match styles based on the existence of an active view transition, and more specifically based on the active view transition being of a certain type.
Sharing styles between view transition pseudo-elements, a way to declare a style once, and use it for multiple view transition pseudo-elements. This includes the view-transition-class property, and additions to named pseudo-elements
This section is non-normative.
2.1.1. Activation With same-document view transitions, the author starts a view transition using JavaScript, by callingstartViewTransition
. In cross-document view transition, what triggers a view transition is a navigation between two documents, as long as the following conditions are met:
Both documents are of the same origin;
The page is visible throughout the entire course of the navigation;
The user initiates the navigation by interacting with the page, e.g. by clicking a link or submitting a form; or by interacting with the browser UI to do a traverse
navigation (back/forward). This excludes, for example, navigations initiated by the URL bar;
the navigation didn’t include cross-origin redirects; and
both documents opted in to cross-document view transitions, using the @view-transition rule.
See the lifecycle section for more details.
2.1.2. Waiting for the new state to stabilize In same-document view transitions, the author can indicate when the new state of the transition is in a stable state by using the callback passed tostartViewTransition
. Since cross-document view transitions are declarative, there is no such explicit promise. Instead, the user agent relies on the render-blocking mechanism to decide when the document has reached a stable state. In this way, the author can use the blocking
attribute, to delay the transition until:
All expected scripts are executed, by using the script’s blocking
attribute on required scripts.
All expected styles are executed, by using the style or link’s blocking
attribute on required styles.
All expected HTML elements are seen by the parser, using an expect
HTMLLinkElement
element.
Note: overusing the render-blocking mechanism could make it so that the old state remains frozen for a long time, resulting in a jarring user experience. To avoid this, it’s advised to ensure that the render-blocking elements are available in a timely manner.
In this example, the last frame of the old document will be shown, and the animation will be delayed, until all the following conditions are met:
style.css
is applied, to ensure the new state has the correct styles
fixup.js
is run, to ensure the presentation is up to date with script-based fixups.
The main-article
section is seen and parsed, to ensure enough of the content is loaded before allowing the transition to proceed.
<!DOCTYPE html> <html> <head> < !-- This will be render-blocking by default --> <link rel="stylesheet" href="style.css"> < !-- Since this script fixes up the layout, marking it as render blocking will ensure it's run before the view transition is activated --> <script async href="fixup.js" blocking="render"></script> < !-- Wait until the main-article element is seen and fully parsed before activating the transition --> <link rel="expect" href="#main-article" blocking="render"> </head> <body> <header>...</header> <main> <article id="main-article">...</article> </main> <article id="secondary-article">...</article> </body> </html>2.1.3. Customization The
ViewTransition
object enables customizing the transition in script. Same-document view transitions use a single ViewTransition
object returned from the startViewTransition
call for the entire lifecycle. Cross-document view transitions have two ViewTransition
objects, one in the old document and one in the new document. 2.1.3.1. Handling the view transition in the old document
The pageswap
event is fired at the last moment before a document is about to be unloaded and swapped by another document. It can be used to find out whether a view transition is about to take place, customize it using types
, make last minute changes to the captured elements, or skip it if necessary. The PageSwapEvent
interface has a viewTransition
object, which would be non-null when the navigation is eligible to a view transition, and a activation
object, providing handy information about the navigation, like the URL after redirects. The transition’s finished
promise can be used for cleaning up after the transition, in case the document is later restored from BFCache.
The pagereveal
event is fired right before presenting the first frame of the new document. It can be used to find out if the view transition is still valid, by querying the viewTransition
attribute. Similar to a same-document view transition, the author can now select different types
, make last minute changes to the captured elements, wait for the transition to be ready
in order to animate it, or skip it altogether.
This section is non-normative.
A successful cross-document view transition goes through the following phases:
In the old Document
:
The user initiates a navigation, by clicking a link, submitting a form, pressing the browser’s back button, etc.
Note: some navigations do not trigger a view-transition, e.g. typing a new address in the URL bar.
When the new Document
is ready to be activated, the pageswap
event is fired.
If the navigation is same origin, has no cross-origin redirects, and the old Document
has opted in to cross-document view transitions, the event’s viewTransition
attribute would be a ViewTransition
object.
The author can now customize the transition, e.g. by mutating its types
, or skip
it altogether.
If the ViewTransition
is not skipped, the state of the old document is captured.
The navigation proceeds: the old Document
is unloaded, and the new Document
is now active.
Then, in the new Document
:
When the new Document
is ready for its first rendering opportunity, an event named pagereveal
is fired on the new Document
, with a viewTransition
attribute.
This ViewTransition
’s
promise is already resolved, and its captured elements are populated from the old updateCallbackDone
Document
.
This is another opportunity for the author to customize the transition, e.g. by mutating its types
, or skip
it altogether.
The state of the new document is captured as the "new" state of the transition.
From this point forward, the transition continues in a similar fashion to a same-document transition, as per activate view transition.
To generate the same cross-fade as in the first example
CSS View Transitions 1 § 1.6 Examples, but across documents, we don’t need JavaScript.
Instead, we opt in to triggering view-transitions on navigation in both page 1 and page 2:
// in both documents: @view-transition { navigation: auto; }
A link from page 1 to or from page 2 would generate a crossfade transition for example 1. To achieve the effect examples 2, 3 & 4, simply put the CSS for the pseudo-elements in both documents.
Note that the
@view-transitionrule can be used together with media queries. For example, this would only perform the transition when the screen width is greater than:
@view-transition { navigation: auto; } @media (max-width: 600px) { navigation: none; }
To achieve the effect in
example 5, we have to do several things:
Opt-in to navigation-triggered view-transitions in both pages.
Pass the click location to the new document, e.g. via sessionStorage
.
Intercept the ViewTransition
object in the new document, using the pagereveal
event.
In both pages:
@view-transition { navigation: auto; }
In the old page:
addEventListener('click', event => { sessionStorage.setItem("lastClickX", event.clientX); sessionStorage.setItem("lastClickY", event.clientY); });
In the new page:
// 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)' } ); })
To choose which elements are captured based on properties of the navigation, and whether certain images are loaded:
In the old page:
window.addEventListener("pageswap", event => { // For example, the page was hidden, or the navigation is cross-document. if (!event.viewTransition) return; // If you don't want view transition for back/forward navigations... if (event.activation.navigationType === "traverse") { event.viewTransition.skipTransition(); } const newURL = new URL(event.activation.entry.url); if (newURL.pathname === "/details" && thumbnail.complete) { thumbnail.classList.add("transition-to-hero"); // This will cleanup the state if the page is restored from BFCache. event.viewTransition.finished.then(() => { thumbnail.classList.remove("transition-to-hero"); }); } });
In the new page:
window.addEventListener("pagereveal", event => { // For example, the page was hidden, the navigation is cross-document, or the transition was skipped in the old document. if (!event.viewTransition) return; const oldURL = new URL(navigation.activation.from.url); if (newURL.pathname === "/list") { event.viewTransition.types.add("coming-from-list"); // This will show the thumbnail until the view transition is finished. if (!hero.complete) { setToThumbnail(hero); event.viewTransition.finished.then(() => { setToFullResolution(hero); }) } } });2.3. Opting in to cross-document view transitions 2.3.1. The @view-transition rule
The @view-transition rule is used by a document to indicate that cross-document navigations should setup and activate a ViewTransition
.
The @view-transition rule has the following syntax:
@view-transition { <declaration-list> }
The @view-transition rule accepts the navigation and types descriptors.
Note: as per default behavior, the @view-transition rule can be nested inside a conditional group rule such as @media or @supports.
When the @view-transition rule changes for Document
document, the user agent must update the opt-in state for outbound transitions given document.
Note: this needs to be cached in the boolean because the result needs to be read in parallel, when navigating.
2.3.2. The navigation descriptorThe 'navigation' descriptor opts in to automatically starting a view transition when performing a navigation of a certain type. Must be present on both the old and new document.
There will be no transition.
The transition will be enabled if the navigation is same-origin, without cross-origin redirects, and whose NavigationType
is
traverse
, or
push
or replace
, with user navigation involvement not equal to "browser UI"
.
Note: Navigations excluded from auto are for example, navigating via the URL address bar or clicking a bookmark, as well as any form of user or script initiated reload
.
This at-rule conforms with the forward-compatible parsing requirement of CSS; conformant parsers that don’t understand these rules will ignore them without error. Any descriptors that are not recognized or implemented by a given user agent, or whose value does not match the grammars given here or in a future version of this specification, must be ignored in their entirety; they do not make the @view-transition rule invalid.
2.3.3. Accessing the @view-transition rule using CSSOMThe CSSViewTransitionRule
represents a @view-transition rule.
[Exposed=Window] interfaceCSSViewTransitionRule
: CSSRule { readonly attribute CSSOMStringnavigation
; [SameObject] readonly attribute FrozenArray<CSSOMString>types
; };
The navigation
getter step is to return the value of the corresponding navigation descriptor if one exists, otherwise the empty string.
The types
getter steps is to return the value of the corresponding types descriptor if one exists, otherwise an empty list.
This section is non-normative.
For simple pages, with a single view transition, setting the view-transition-name property on participating elements should be sufficient. However, in more complex scenarios, the author might want to declare various view transitions, and only run one of them simultaneously. For example, sliding the whole page when clicking on the navigation bar, and sorting a list when one of its items is dragged.
To make sure each view transition only captures what it needs to, and different transitions don’t interfere with each other, this spec introduces the concept of active types, alongside the :active-view-transition and :active-view-transition-type() pseudo-classes.
:active-view-transition matches the document element when it has an active view transition, and :active-view-transition-type() matches the document element if the types in the selectors match the active view transition’s active types.
The ViewTransition
’s active types are populated in one of the following ways:
Passed as part of the arguments to startViewTransition(callbackOptions)
Mutated at any time, using the transition’s types
Declared for a cross-document view transition, using the types descriptor.
For example, the developer might start a transition in the following manner:
document.startViewTransition({update: updateTheDOMSomehow, types: ["slide-in", "reverse"]});
This will activate any of the following selectors:
:root:active-view-transition-type(slide-in) {} :root:active-view-transition-type(reverse) {} :root:active-view-transition-type(slide-in, reverse) {} :root:active-view-transition-type(slide-in, something-else) {} :root:active-view-transition {}
While starting a transition without providing transition types, would only activate ':active-view-transition'':
document.startViewTransition(updateTheDOMSomehow); // or document.startViewTransition({update: updateTheDOMSomehow});
/* This would be active */ :root { } :root:active-view-transition {} /* This would not be active */ :root:active-view-transition-type(slide-in) {} :root:active-view-transition-type(any-type-at-all-except-star) {}3.3. Selecting based on the active view transition 3.3.1. The :active-view-transition pseudo-class
The :active-view-transition pseudo-class applies to the root element of the document, if it has an active view transition.
The specificity of an :active-view-transition is one pseudo-class selector.
An :active-view-transition pseudo-class matches the document element when its node document has an non-null active view transition.
3.3.2. The :active-view-transition-type() pseudo-classThe :active-view-transition-type() pseudo-class applies to the root element of the document, if it has a matching active view transition. It has the following syntax definition:
:active-view-transition-type(<custom-ident>#)
The specificity of an :active-view-transition-type() is one pseudo-class selector.
An :active-view-transition-type() pseudo-class matches the document element when its node document has an non-null active view transition, whose active types contains at least one of the <custom-ident> arguments.
3.4. Changing the types of an ongoing view transitionThe ViewTransition
interface is extended as follows:
[Exposed=Window] interfaceViewTransitionTypeSet
{ setlike<DOMString>; }; [Exposed=Window] partial interface ViewTransition { attribute ViewTransitionTypeSettypes
; };
The ViewTransitionTypeSet
object represents a set of strings, without special semantics.
Note: a ViewTransitionTypeSet
can contain strings that are invalid for :active-view-transition-type, e.g. strings that are not a <custom-ident>.
The types
getter steps are to return this’s active types.
The types descriptor
The 'types' descriptor sets the active types for the transition when capturing or performing the transition, equivalent to calling startViewTransition(callbackOptions)
with that types
.
Note: the types descriptor only applies to the Document
in which it is defined. The author is responsible for using their chosen set of types in both documents.
This section is non-normative.
When styling multiple elements in the DOM in a similar way, it is common to use the class attribute: setting a name that’s shared across multiple elements, and then using the class selector to declare the shared style.
The view transition pseudo-elements (e.g. view-transition-group()) are not defined in the DOM, but rather by using the view-transition-name property. For that purpose, the view-transition-class' CSS property provides view transitions with the equivalent of HTML classes. When an element with a view-transition-name also has a view-transition-class value, that class would be selectable by the pseudo-elements, as per the examples.
4.2. ExamplesThis example creates a transition with each box participating under its own name, while applying a 1-second duration to the animation of all the boxes:
<div class="box" id="red-box"></div> <div class="box" id="green-box"></div> <div class="box" id="yellow-box"></div>
div.box { view-transition-class: any-box; width: 100px; height: 100px; } #red-box { view-transition-name: red-box; background: red; } #green-box { view-transition-name: green-box; background: green; } #yellow-box { view-transition-name: yellow-box; background: yellow; } /* The following style would apply to all the boxes, thanks to 'view-transition-class' */ ::view-transition-group(*.any-box) { animation-duration: 1s; }4.3. The view-transition-class property
The view-transition-class can be used to apply the same style rule to multiple named view transition pseudo-elements which may have a different view-transition-name. While view-transition-name is used to match between the element in the old state with its corresponding element in the new state, view-transition-class is used only to apply styles using the view transition pseudo-elements (::view-transition-group(), ::view-transition-image-pair(), ::view-transition-old(), ::view-transition-new()).
Note that view-transition-class by itself doesn’t mark an element for capturing, it is only used as an additional way to style an element that already has a view-transition-name.
No class would apply to the named view transition pseudo-elements generated for this element.
All of the specified <custom-ident> values (apart from none) are applied when used in named view transition pseudo-element selectors. none is an invalid <custom-ident> for view-transition-class, even when combined with another <custom-ident>.
Each 'view transition class' is a tree-scoped name.
Note: If the same view-transition-name is specified for an element both in the old and new states of the transition, only the view-transition-class values from the new state apply. This also applies for cross-document view transitions: classes from the old document would only apply if their corresponding view-transition-name was not specified in the new document.
The named view transition pseudo-elements (view-transition-group(), view-transition-image-pair(), view-transition-old(), view-transition-new()) are extended to support the following syntax:
::view-transition-group(<pt-name-and-class-selector>) ::view-transition-image-pair(<pt-name-and-class-selector>) ::view-transition-old(<pt-name-and-class-selector>) ::view-transition-new(<pt-name-and-class-selector>)
where <pt-name-selector> works as previously defined, and <pt-name-and-class-selector> has the following syntax definition:
<pt-name-and-class-selector> = <pt-name-selector> <pt-class-selector>? | <pt-class-selector> <pt-class-selector> = ['.' <custom-ident>]+
When interpreting the above grammar, white space is forbidden:
Between <pt-name-selector> and <pt-class-selector>
Between any of the components of <pt-class-selector>.
A named view transition pseudo-element selector which has one or more <custom-ident> values in its <pt-class-selector> would only match an element if the class list value in named elements for the pseudo-element’s view-transition-name contains all of those values.
The specificity of a named view transition pseudo-element selector with either:
a <pt-name-selector> with a <custom-ident>; or
a <pt-class-selector> with at least one <custom-ident>,
is equivalent to a type selector.
The specificity of a named view transition pseudo-element selector with a * argument and with an empty <pt-class-selector> is zero.
5. Extendingdocument.startViewTransition()
dictionary6. Determining view-transition-name automatically 6.1. OverviewStartViewTransitionOptions
{ ViewTransitionUpdateCallback?update
= null; sequence<DOMString>?types
= null; }; partial interface Document { ViewTransition startViewTransition(optional (ViewTransitionUpdateCallback or StartViewTransitionOptions)callbackOptions
= {}); };
This section is non-normative.
For an element to participate in a view transition, it needs to receive a unique view-transition-name. This can be tedious and verbose when multiple elements are involved in the same view transition, especially in cases where many of those are same-element transitions, as in, the element has the same view-transition-name in the old and new state.
To make this easier, setting the view-transition-name to auto would generate a view-transition-name for the element, or take it from the element’s id if present.
6.2. ExamplesIn this example, view transition is used to sort a list in an animated way:
<ul> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> <li>Item 4</li> ... </ul>
Ordinarily, each of these items would have to receive a unique view-transition-name:
li:nth-child(1) { view-transition-name: item1; } li:nth-child(2) { view-transition-name: item2; } li:nth-child(3) { view-transition-name: item3; } li:nth-child(4) { view-transition-name: item4; } ...
With auto or match-element, this CSS would work:
li { view-transition-name: auto; /* or */ view-transition-name: match-element; }
The auto and match-element keywords have a minor difference, where auto would use the element’s id as the view-transition-name if it exists, making it potentially work across documents, while match-element only matches based on element identity.
6.3. Additions to view-transition-nameIn addition to the existing values, the view-transition-name also accepts an auto keyword. To resolve the used value of view-transition-name for element:
Let computed be the computed value of view-transition-name.
If computed is none, return null.
If computed is a <custom-ident>, return computed.
Assert: computed is auto or match-element.
If computed is auto, element has an associated id, and computed is associated with the same root as element’s root, then return a unique string. Two elements with the same id must return the same string, regardless of their node document.
Note: this means that a ::part() pseudo-element wouldn’t resolve to its matching element’s id.
Return a unique string. The string should remain consistent and unique for this element and Document
, at least for the lifetime of element’s node document’s active view transition.
Note: this string is not web-observable, and is used for addressing the element in internal algorithms.
Note: When used in a cross-document view transition, generated auto values never match, resulting in separate ::view-transition-group() pseudo-elements, one exiting and one entering.
A view-transition-name generated by auto is a tree-scoped name.
7. Nested view-transition groups 7.1. OverviewThis section is non-normative.
By default, setting view-transition-name
on multiple elements generates a flat view transition tree, where all the ::view-transition-group() pseudo-elements are children of the ::view-transition pseudo-element. This is sufficient for many simple use-cases, but there are some styling use-cases that cannot be achieved with a flat tree. The most prominent use-case is clipping: with a flat tree, all pseudo-elements are clipped to the snapshot containing block, so clipping elements in the normal tree would lose their clipping during the view-transition, resulting in a broken visual effect. The effects that have can have an unexpected visual effect in a flat tree:
Clipping (overflow, clip-path, border-radius): clipping affects the children of the element.
opacity, mask-image and filter: These effects that are designed to work on a fully rasterized image of a tree, rather than on each item individually.
3D transforms (transform-style, transform, perspective): to display the full range of 3D transform animations, some hierarchy needs to be kept.
To enable these use cases, this specification introduces the concept of nesting view-transition pseudo-elements. By using the view-transition-group CSS property, the author can assign a "parent group" for a generated ::view-transition-group() pseudo-element, creating a hierarchy in the view transition tree.
7.2. ExamplesThis example creates a transition where the
view transition treeis nested instead of flat:
<section class="container"> <article>Content</article> </section>
.container { view-transition-name: container; } .container, ::view-transition-group(container) { clip-path: circle(); } article { view-transition-name: article; view-transition-group: container; }
By applying the clip-path to both the containing element and its generated pseudo-element, we preserve the clip during the transition, and by applying view-transition-group to the internal element referencing the container, we make the tree "nested" in a way that would apply this clipping.
This specification introduces no new privacy considerations.
To prevent cross-origin issues, at this point cross-document view transitions can only be enabled for same-origin navigations. As discussed in WICG/view-transitions#200, this still presents two potential threats:
This appendix is informative.
Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.
All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]
Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example"
, like this:
Informative notes begin with the word “Note” and are set apart from the normative text with class="note"
, like this:
Note, this is an informative note.
Advisements are normative sections styled to evoke special attention and are set apart from other normative text with <strong class="advisement">
, like this: UAs MUST provide an accessible alternative.
A style sheet is conformant to this specification if all of its statements that use syntax defined in this module are valid according to the generic CSS grammar and the individual grammars of each feature defined in this module.
A renderer is conformant to this specification if, in addition to interpreting the style sheet as defined by the appropriate specifications, it supports all the features defined by this specification by parsing them correctly and rendering the document accordingly. However, the inability of a UA to correctly render a document due to limitations of the device does not make the UA non-conformant. (For example, a UA is not required to render color on a monochrome monitor.)
An authoring tool is conformant to this specification if it writes style sheets that are syntactically correct according to the generic CSS grammar and the individual grammars of each feature in this module, and meet all other conformance requirements of style sheets as described in this module.
So that authors can exploit the forward-compatible parsing rules to assign fallback values, CSS renderers must treat as invalid (and ignore as appropriate) any at-rules, properties, property values, keywords, and other syntactic constructs for which they have no usable level of support. In particular, user agents must not selectively ignore unsupported component values and honor supported values in a single multi-value property declaration: if any value is considered invalid (as unsupported values must be), CSS requires that the entire declaration be ignored.
Once a specification reaches the Candidate Recommendation stage, non-experimental implementations are possible, and implementors should release an unprefixed implementation of any CR-level feature they can demonstrate to be correctly implemented according to spec.
To establish and maintain the interoperability of CSS across implementations, the CSS Working Group requests that non-experimental CSS renderers submit an implementation report (and, if necessary, the testcases used for that implementation report) to the W3C before releasing an unprefixed implementation of any CSS features. Testcases submitted to W3C are subject to review and correction by the CSS Working Group.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.3