::view-transition

Avatar of Geoff Graham
Geoff Graham on (Updated on )

The CSS ::view-transition pseudo-element is the top-level — or “root” — containing all animated transitions defined as CSS view transitions on the page.

::view-transition {
  position: fixed;
  inset: 0;
}

Syntax

::view-transition {
  /* Styles */
}

It’s worth noting that ::view-transition holds all view transitions on the page (we’ll get to that in a bit), so you’re likely to see it used most often used unchained to a selector like the example above rather than, say, this:

/* 👎 */
blockquote::view-transition {
  /* Styles */
}

Left as-is, ::view-transition is scoped to the <html> element:

html::view-transition {
  /* Styles */
}

Default styles

Like many semantic HTML elements and pseudo-elements, browsers apply a set of default styles to ::view-transition.

::view-transition {
  position: fixed;
  inset: 0;
}

So, if we want to position ::view-transition ourselves, these are the styles we have to override in our own stylesheet.

It’s a “tree-abiding” pseudo-element

In other words, it’s effectively a wrapper that serves as the parent pseudo-element for others below it. The spec calls this a “tree-abiding pseudo-element” which means it contains other pseudos that can be used to style view transitions directly in CSS.

In this case, ::view-transition contains all of the view transitions on the page, organized in groups.

::view-transition
├─ ::view-transition-group(name)
│  └─ ::view-transition-image-pair(name)
│     ├─ ::view-transition-old(name)
│     └─ ::view-transition-new(name)
├─ ::view-transition-group(name)
│  └─ ::view-transition-image-pair(name)
│     ├─ ::view-transition-old(name)
│     └─ ::view-transition-new(name)
│ /* and so one... */

This way, we can define styles that apply to all view transitions together with ::view-transition and individually with ::view-transition-group.

How it fits into the view transitions process

It’s a good idea to be familiar with the steps that a view transition takes for context on where this ::view-transition tree fits in with everything.

It’s right there in Step 4 that we’re talking about.

It introduces a new stacking layer!

You know how we can use the CSS z-index property to layer elements one on top of another, like in a three-dimensional space?

We call this a “stacking context” and it happens when we declare a position on an element. In this case, both .child elements are in a stacking context where we’re using z-index to determine which element is above the other in the stack. CSS uses this information to determine in what order it applies styles:

  1. Elements with a negative stack level, typically elements with z-index: -1
  2. Elements with a position value of static.
  3. Elements with a stack level of 0, typically positioned elements with a z-index value of auto.
  4. Elements with positive stack levels, e.g. a positioned element with a z-index value of 1 or higher.

That third layer is called the “top layer” since it’s right smack dab in between layers positive and negative layers. This is where the <html> and <body> sit.

Well, it turns out that ::view-transition introduces a new stacking layer of its own, that is applied after everything else, i.e., it comes after the layer with the highest number:

  1. Elements with a negative stack level, typically elements with z-index: -1
  2. Elements with a position value of static.
  3. Elements with a stack level of 0, typically positioned elements with a z-index value of auto.
  4. Elements with positive stack levels, e.g. a positioned element with a z-index value of 1 or higher.
  5. View transitions

Here’s exactly how the specification describes it:

The ::view-transition pseudo-element generates a new stacking context, called the view transition layer, which paints after all other content of the document (including any content rendered in the top layer), after any filters and effects that are applied to such content. (It is not subject to such filters or effects, except insofar as they affect the rendered contents of the ::view-transition-old() and ::view-transition-new() pseudo-elements.)

CSS View Transitions Module Level 1, 4.2. View Transition Painting Order

What’s the big deal, you ask? This means that a view transition’s styles are painted after everything else, ensuring that they are never buried beneath other layers. This way, we never have to juggle between view transition styles and the styles of the elements on a page with z-index to make sure they’re visible. But this only takes effect if (1) there are view transitions on the page and (2) when the view transition is running. Once the transition ends, its stacking context is gone.

Specification

The CSS ::view-transition pseudo-element is defined in the View Transitions Module Level 1 specification. It’s labeled a Candidate Recommendation Snapshot which means it’s been widely reviewed and is intended to become an official W3C Recommendation, but is still being tested in the wild.

The specification further states:

This document is intended to become a W3C Recommendation; it will remain a Candidate Recommendation at least until 5 December 2023 to gather additional feedback.

That date has passed as of this writing, so keep an eye on the document’s status as it makes its way toward becoming a recommended feature.

Browser support

Data on support for the view-transitions feature across the major browsers from caniuse.com

If you need to support older browsers that do not support ::view-transition, try using @supports to check whether or not the browser recognizes the view-transition-name property:

/* Apply these styles only if View Transitions are *NOT* supported */
@supports not (view-transition-name: none) {
  /* Fallback Styles */
}

More information