CSS View Transitions Module Level 2

Editor’s Draft,

More details about this document
This version:
https://drafts.csswg.org/css-view-transitions-2/
Latest published version:
https://www.w3.org/TR/css-view-transitions-2/
Feedback:
CSSWG Issues Repository
Inline In Spec
Editors:
Noam Rosenthal (Google)
Khushal Sagar (Google)
Vladimir Levin (Google)
Tab Atkins-Bittner (Google)
Suggest an Edit for this Spec:
GitHub Editor

Abstract

This module defines how the View Transition API works with cross-document navigations.

CSS is a language for describing the rendering of structured documents (such as HTML and XML) on screen, on paper, etc.

Status of this document

This is a public copy of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C. Don’t cite this document other than as work in progress.

Please send feedback by filing issues in GitHub (preferred), including the spec code “css-view-transitions” in the title, like this: “[css-view-transitions] …summary of comment…”. All issues and comments are archived. Alternately, feedback can be sent to the (archived) public mailing list www-style@w3.org.

This document is governed by the 12 June 2023 W3C Process Document.

1. Introduction

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.

1.1. Lifecycle

This section is non-normative.

A successful cross-document view transition goes through the following phases:

  1. The user navigates, by clicking a link, submitting a form, traversing history using the browser UI, etc.

  2. Once it’s time to unload the old document, if the navigation is same origin and the old Document has opted in to cross-document view-transitions, the old state is captured.

  3. An event named reveal is fired on the new Document, with a viewTransition property, which is a ViewTransition object. This ViewTransition's updateCallbackDone is already resolved, and its captured elements are populated from the old Document.

  4. Right before the new Document has the first rendering opportunity, its state is captured as the "new" state.

  5. From this point forward, the transition continues as if it was a same-document transition, as per activate view transition.

1.2. Examples

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 auto-view-transitions in both page 1 and page 2:

// in both documents:
@auto-view-transitions {
  same-origin: enable;
}

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.

To achieve the effect in example 5, we have to do several things:

In both pages:

@auto-view-transitions {
  same-origin: enable;
}

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("reveal", 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)'
    }
  );
})

2. CSS rules

2.1. The @auto-view-transition rule

The @auto-view-transition rule is used by a document to indicate that cross-document navigations should setup and activate a ViewTransition. To take effect, it must be present in the old document when unloading, and in the new document when it is being revealed.

2.2. @auto-view-transition rule grammar

@auto-view-transition rules are parsed according to the following grammar, plus the additional rules noted below:

@auto-view-transition = @auto-view-transition { <declaration-rule-list> }

2.3. The same-origin property

Name: same-origin
For: @auto-view-transition
Value: enabled | disabled
Initial: disabled

The 'same-origin' property opts in to automatically performing a view transition when performing a same origin navigation. It needs to be enabled both in the old document (when unloading) and in the new document (when ready to render).

disabled

There will be no transition.

enabled

The transition will be enabled if the navigation is same-origin, without cross-origin redirects.

3. API

3.1. The PageRevealEvent

Note: this should go in the HTML spec. See Issue 9315.

[Exposed=Window]
interface PageRevealEvent : Event {
  readonly attribute ViewTransition? viewTransition;
};

Note: this event is fired when revealing a document.

The viewTransition getter steps are to return the inbound cross-document view-transition for this’s relevant global object’s associated document.

4. Algorithms

4.1. Data Structures

4.1.1. Additions to Document

A Document additionally has:

is revealed

a boolean, initially false.

4.1.2. Additions to ViewTransition ## {#view-transitions-extension}

A ViewTransition additionally has:

is inbound cross-document transition

a boolean, initially false.

4.2. Monkey patches to HTML

Prepend a step at the beginning of the task queued on navigable’s active window when applying the history step (14.11.1, here):

If changingNavigationContinuation update-only is false, then setup outbound cross-document view transition given oldDocument, newDocument and the remaining steps and return from these steps.

Note: This would wait until a transition is captured or skipped before proceeding to unloading the old document and activating the new one.

Run the following step in updating the renedering, before running the animation frame callbacks:
  1. For each fully active Document doc in docs, reveal doc.

Run the following step at the end of reactivate:
  1. Set document’s is revealed to false.

To reveal Document document:
  1. If document’s is revealed is true, then return.

  2. Let transition be the result of getting the inbound cross-document view-transition for document.

  3. If transition is not null and document does not opt in to cross-document view transitions, then skip transition and set transition to null.

  4. Fire a new event named reveal on document’s relevant global object, using PageRevealEvent.

  5. If transition is not null, then activate transition.

  6. Set document’s is revealed to true.

4.3. Setting up and activating the cross-document view transition

To setup outbound cross-document view transition given a Document oldDocument, a Document newDocument, and onReady, which is an algorithm accepting nothing:
  1. If oldDocument’s origin is not same origin as newDocument’s origin then call onReady and return.

  2. If newDocument was created via cross-origin redirects is true and newDocument’s latest entry is null, then call onReady and return.

    Note: A document with a non-null latest entry is being reactivated, in which case we don’t need to check for cross-origin redirects.

  3. If oldDocument does not opt in to cross-document view transitions, then call onReady and return.

    Note: We don’t know yet if newDocument has opted in, as it might not be parsed yet. We check the opt-in for newDocument when it is revealed.

  4. If oldDocument’s active view transition is not null, then skip oldDocument’s active view transition with an "AbortError" DOMException in oldDocument’s relevant Realm.

    Note: this means that any running transition would be skipped when the document is ready to unload.

  5. Let outboundTransition be a new ViewTransition object in oldDocument’s relevant Realm, whose process old state captured is set to the following steps:

    should we check for the opt-in again, in case there was a CSSOM change in a requestAnimationFrame callback?

    1. If outboundTransition’s phase is "done", then call onReady and return.

    2. Assert: outboundTransition’s phase is "pending-capture".

    3. Clear view transition outboundTransition.

      Note: The ViewTransition object on the old Document should be destroyed after its state has been copied to the new Document below. We explicitly clear it here since the old Document may be cached by the UA.

    4. Queue a global task on the DOM manipulation task source given newDocument’s relevant global object, to perform the following step:

      1. Let newDocument’s active view transition be a new ViewTransition in newDocument’s relevant Realm, whose named elements is outboundTransition’s named elements, initial snapshot containing block size is outboundTransition’s initial snapshot containing block size, and whose is inbound cross-document transition is true.

      2. Call the update callback for newDocument’s active view transition.

      3. Call onReady.

    Note: outboundTransition is not exposed to JavaScript, it is used only for capturing the state of the old document.

  6. Set oldDocument’s active view transition to outboundTransition.

    Note: The process continues in setup view transition, via perform pending transition operations, which is called in .

To get the inbound cross-document view-transition for a Document document:
  1. Let transition be document’s active view transition.

  2. If transition is null or transition’s is inbound cross-document transition is false, then return null.

    Note: transition’s is inbound cross-document transition would be false if a same-document transition was started before the page was revealed.

  3. Return transition.

A Document document is said to opt in to cross-document view transitions if the computed value of same-origin is enabled.

Privacy Considerations

This specification introduces no new privacy considerations.

Security 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:

  1. The cross-origin isolated capability in both documents might be different. This can cause a situation where a Document that is cross-origin isolated can read image data from a document that is not cross-origin isolated. This is already mitigated in [[css-view-transitions-1#sec], as the same restriction applies for captured cross-origin iframes.

  2. A same-origin navigation might still occur via a cross-origin redirect, e.g. https://example.com links to https://auth-provider.com/ which redirects back to https://example.com/loggedin.

    This can cause a (minor) situation where the cross-origin party would redirect the user to an unexpected first-party URL, causing an unexpected transition and obfuscating that fact that there was a redirect. To mitigate this, currently view transitions are disabled for navigations if the Document was created via cross-origin redirects. Note that this check doesn’t apply when the Document is being reactivated, as in that case the cross-origin redirect has already taken place.

    Note: this only applies to server-side redirects. A client-side redirect, e.g. using [^meta/http-equiv/refresh^], is equivalent to a new navigation.

  3. This feature exposes more information to CSS, as so far CSS was not aware of anything navigation-related. This can raise concerns around safety 3rd-party CSS. However, as a general rule, 3rd-party stylesheets should come from trusted sources to begin with, as CSS can learn about the document or change it in many ways.

See Issue #8684 and WICG/view-transitions#200 for detailed discussion.

Conformance

Document conventions

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:

This is an example of an informative example.

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.

Tests

Tests relating to the content of this specification may be documented in “Tests” blocks like this one. Any such block is non-normative.


Conformance classes

Conformance to this specification is defined for three conformance classes:

style sheet
A CSS style sheet.
renderer
A UA that interprets the semantics of a style sheet and renders documents that use them.
authoring tool
A UA that writes a style sheet.

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.

Partial implementations

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.

Implementations of Unstable and Proprietary Features

To avoid clashes with future stable CSS features, the CSSWG recommends following best practices for the implementation of unstable features and proprietary extensions to CSS.

Non-experimental implementations

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.

Further information on submitting testcases and implementation reports can be found from on the CSS Working Group’s website at https://www.w3.org/Style/CSS/Test/. Questions should be directed to the public-css-testsuite@w3.org mailing list.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-CASCADE-5]
Elika Etemad; Miriam Suzanne; Tab Atkins Jr.. CSS Cascading and Inheritance Level 5. URL: https://drafts.csswg.org/css-cascade-5/
[CSS-SYNTAX-3]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. URL: https://drafts.csswg.org/css-syntax/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 4. URL: https://drafts.csswg.org/css-values-4/
[CSS-VIEW-TRANSITIONS-1]
Tab Atkins Jr.; Jake Archibald; Khushal Sagar. CSS View Transitions Module Level 1. URL: https://drafts.csswg.org/css-view-transitions-1/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

Property Index

No properties defined.

@auto-view-transition Descriptors

Name Value Initial
same-origin enabled | disabled disabled

IDL Index

[Exposed=Window]
interface PageRevealEvent : Event {
  readonly attribute ViewTransition? viewTransition;
};

Issues Index

should we check for the opt-in again, in case there was a CSSOM change in a requestAnimationFrame callback?
MDN

view-transition-name

In only one current engine.

FirefoxNoneSafariNoneChrome111+
Opera?Edge111+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?