Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-view-transitions-1] Define pseudo-nesting and naming #8126

Merged
merged 13 commits into from
Jan 12, 2023
167 changes: 95 additions & 72 deletions css-view-transitions-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -197,40 +197,55 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

# Pseudo-elements # {#pseudo}

The following <dfn export>view-transition pseudo-elements</dfn> represent the various items being animated.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This dfn was no longer needed.

## Pseudo-element root ## {#pseudo-root}

The ''::view-transition'' pseudo-element acts as a grouping element for other [=view-transition pseudo-elements=]
and has the document's [=document element=] as its [=originating element=].
Note: This is a general definition for trees of pseudo-elements. If other features need this behavior, these definitions will be moved to [[css-pseudo-4]].

Note: For example, '':root::view-transition'' selector matches this pseudo-element,
but ''div::view-transition'' does not.
A <dfn>pseudo-element root</dfn> is a type of [=tree-abiding pseudo-element=] that is the [=tree/root=] in a [=tree=] of [=tree-abiding pseudo-elements=],
khushalsagar marked this conversation as resolved.
Show resolved Hide resolved
known as the <dfn>pseudo-element tree</dfn>.

Other [=view-transition pseudo-elements=] take a <<pt-name-selector>> argument
to specify which elements named with 'view-transition-name' are affected.
The [=pseudo-element tree=] defines the document order of its [=tree/descendant=] [=tree-abiding pseudo-elements=].

There can be multiple pseudo-elements of the same type,
one for each 'view-transition-name' participating in a transition.
When a [=pseudo-element=] [=tree/participates=] in a [=pseudo-element tree=],
its [=originating pseudo-element=] is its [=tree/parent=].

The <<pt-name-selector>> is defined as follows:
If a [=tree/descendant=] |pseudo| of a [=pseudo-element root=] has no other [=tree/siblings=],
khushalsagar marked this conversation as resolved.
Show resolved Hide resolved
then '':only-child'' matches that |pseudo|.

Note: This means that `::view-transition-new(ident):only-child` will only select `::view-transition-new(ident)` if the parent `::view-transitions-image-pair(ident)` contains a single [=tree/child=].
As in, there is no [=tree/sibling=] `::view-transition-old(ident)`.

## Named view-transition pseudo-elements ## {#named-view-transition-pseudo}

A <dfn>named view-transition pseudo-element</dfn> is a type of [=tree-abiding pseudo-elements=].

It has a <dfn for="named view-transition pseudo-element">view-transition name</dfn>,
a string.

Their selector takes a <<pt-name-selector>> argument.

<pre class=prod>
<dfn>&lt;pt-name-selector></dfn> = '*' | <<custom-ident>>
</pre>

A value of ''*'' makes the corresponding selector apply to all pseudo elements of the specified type.
The specificity of a view-transition selector with a ''*'' argument is zero.
The selector matches if the <<pt-name-selector>> is `*` or matches the [=named view-transition pseudo-element=]'s [=named view-transition pseudo-element/view-transition name=].

The <<custom-ident>> value makes the corresponding selector apply to exactly one pseudo element of the specified type,
namely the pseudo-element that is created as a result of the 'view-transition-name' property on an element with the same <<custom-ident>> value.
The specificity of a view-transition selector with a <<custom-ident>> argument is the same as for other pseudo-elements,
and is equivalent to a [=type selector=].

The following describes all of the [=view-transition pseudo-elements=] and their function:
The specificity of a view-transition selector with a `*` argument is zero.

Note: The [=named view-transition pseudo-element/view-transition name=] is set to the 'view-transition-name' that triggered its creation.

## View transition pseudo-elements ## {#view-transition-pseudos}

: <dfn>::view-transition</dfn>
:: This pseudo-element is the grouping container of all the other [=view-transition pseudo-elements=].
:: A [=tree-abiding pseudo-element=] that is also
a [=pseudo-element root=].
Its [=originating element=] is the document's [=document element=].

Its [=containing block=] is the [=snapshot viewport=].

The following is added to the [=HTML user agent style sheet=]:

```css
Expand All @@ -240,15 +255,18 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;
}
```

Note: This pseudo-element provides a containing block for all ''::view-transition-group()'' pseudo-elements.
The aim of the style is to size the pseudo-element to cover the [=snapshot viewport=]
and position all ''::view-transition-group()'' pseudo-elements relative to the [=snapshot viewport origin=].
<div class="note">
This pseudo-element provides a containing block for all ''::view-transition-group()'' pseudo-elements.
The aim of the style is to size the pseudo-element to cover the [=snapshot viewport=]
and position all ''::view-transition-group()'' pseudo-elements relative to the [=snapshot viewport origin=].
</div>

: <dfn>::view-transition-group( <<pt-name-selector>> )</dfn>
:: One of these pseudo-elements exists for each 'view-transition-name' in a view transition,
and holds the rest of the pseudo-elements corresponding to this 'view-transition-name'.
:: A [=tree-abiding pseudo-element=]
that is also a [=named view-transition pseudo-element=],
and [=tree/participates=] in a [=pseudo-element tree=].

Its [=originating element=] is the ''::view-transition'' pseudo-element.
It is selected from its [=ultimate originating element=], the [=document element=].
Copy link
Collaborator

@cdoublev cdoublev Dec 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change, ie. without defining ::view-transition as the originating pseudo-element of ::view-transition-group(), it is not clear whether the latter is still a valid sub-pseudo-element of the former, ie. whether ::view-transition::view-transition-group(name) is still valid, even if I do not think there are usefull use cases for such explicit selection (unlike with ::marker, which selects ::before::marker and ::after::marker) (edit: see next comment).

Maybe the intention is precisely to make it invalid?

For CSS parser/preprocessor authors, it makes a difference since invalid sub-pseudo-elements makes the selector invalid. I do not need to be explicitly defined, but I just would like to get a confirmation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definition also appears in this PR:

When a [=pseudo-element=] |pseudo| is part of a [=pseudo-element parent=] |parent|'s [=pseudo-element parent/children=], then |pseudo|'s [=originating pseudo-element=] is |parent|.

But, it's intended that ::view-transition::view-transition-group(name) is invalid. We might do something with more tree-like selectors later.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I came accross this note in CSS Lists and Counters: an originating element that is a pseudo-element needs to be explicitly specified in the selector. So the examples with html::view-transition-*() would be incorrect? ::before::marker would be selected with ::marker if this were not required, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We explicitly resolved on a syntax which allows selecting these pseudo-elements directly from html, for example html::view-transition-group(foo) here: #7788 (comment).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I got it, sorry. Assuming :div() exists, .foo:div(.bar) would be equivalent to .foo div.bar, but there is no such equivalence with view transition pseudo-elements. The note in CSS List and Counters must not apply to functional pseudo-element.


The following is added to the [=HTML user agent style sheet=]:

Expand All @@ -270,15 +288,16 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;
from the size of the old element's [=border box=] to that of the new element's [=border box=].
Also the element's 'transform' is animated from the old element's screen space transform to the new element's screen space transform.
This style is generated dynamically since the values of animated properties are determined at the time that the transition begins.
</div>

Issue: The selector for this and subsequently defined pseudo-elements is likely to change to indicate position in the pseudo-tree hierarchy.
This is only ever a [=tree/child=] of a ''::view-transition''.
</div>

: <dfn>::view-transition-image-pair( <<pt-name-selector>> )</dfn>
:: One of these pseudo-elements exists for each view-transition-name being in a view transition,
and holds the images of the old and new elements.
:: A [=tree-abiding pseudo-element=]
that is also a [=named view-transition pseudo-element=],
and [=tree/participates=] in a [=pseudo-element tree=].

Its [=originating element=] is the ''::view-transition-group()'' pseudo-element with the same transition-name.
It is selected from its [=ultimate originating element=], the [=document element=].

The following is added to the [=HTML user agent style sheet=]:

Expand All @@ -292,14 +311,17 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;
}
```

Note: The aim of the style is to position the element to occupy the same space as its ''::view-transition-group()'' element.
Note: This is only ever a [=tree/child=] of a ''::view-transition-group()''.

: <dfn>::view-transition-old( <<pt-name-selector>> )</dfn>
:: One of these pseudo-elements exists for each element in the old DOM being animated by the view transition,
and is a [=replaced element=] displaying the old element's snapshot image.
It has [=natural dimensions=] equal to the snapshot's size.
:: A [=tree-abiding pseudo-element=]
that is also a [=named view-transition pseudo-element=],
and [=tree/participates=] in a [=pseudo-element tree=].

Its [=originating element=] is the ''::view-transition-image-pair()'' pseudo-element with the same transition-name.
It is selected from its [=ultimate originating element=], the [=document element=].

It is a [=replaced element=] displaying the old element's snapshot image.
It has [=natural dimensions=] equal to the snapshot's size.

The following is added to the [=HTML user agent style sheet=]:

Expand All @@ -320,27 +342,25 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

Note: Additional styles in the [=document/view transition style sheet=] added to animate these pseudo-elements are detailed in [=setup transition pseudo-elements=] and [=update pseudo-element styles=].

Note: This is only ever a [=tree/child=] of a ''::view-transition-image-pair()'', and never has any [=tree/children=].

: <dfn>::view-transition-new( <<pt-name-selector>> )</dfn>
:: Identical to ''::view-transition-old()'',
except it deals with the new element instead.

The precise tree structure, and in particular the order of sibling pseudo-elements,
Note: The precise tree structure, and in particular the order of sibling pseudo-elements,
is defined in the [=setup transition pseudo-elements=] algorithm.

# Concepts # {#concepts}

## Phases ## {#phases-concept}

<dfn>Phases</dfn> represent an ordered sequence of states.
Since [=phases=] are ordered, prose can refer to phases <dfn for="phases">before</dfn> a particular phase, meaning they appear earlier in the sequence,
or <dfn for="phases">after</dfn> a particular phase, meaning they appear later in the sequence.
Since [=phases=] are ordered, prose can refer to phases <dfn for="phases">before</dfn> a particular phase, meaning they appear earlier in the sequence.
<!-- or <dfn for="phases">after</dfn> a particular phase, meaning they appear later in the sequence. -->

The initial phase is the first item in the sequence.

Note: For the most part, a developer using this API does not need to worry about the different phases, since they progress automatically.
It is, however, important to understand what steps happen in each of the phases: when the snapshots are captured, when pseudo-element DOM is created, etc.
The description of the phases below tries to be as precise as possible, with an intent to provide an unambiguous set of steps for implementors to follow in order to produce a spec-compliant implementation.

## The snapshot viewport ## {#snapshot-viewport-concept}

The <dfn>snapshot viewport</dfn> covers all areas of the window that could potentially display web content.
Expand Down Expand Up @@ -388,10 +408,6 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

- The [=view-transition layer=] paints after the stacking context for the [=document element=] and [=top layer=].

- The [=view-transition layer=] is positioned at the [=snapshot viewport origin=],
and is the same size as the [=snapshot viewport=].
As in, it covers the [=snapshot viewport=].

Note: The intent of the feature is to be able to capture the contents of the page, which includes the top layer elements.
In order to accomplish that, the [=view-transition layer=] cannot be a part of the captured top layer context,
since that results in a circular dependency.
Expand Down Expand Up @@ -466,6 +482,14 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;
Initially a new [=style sheet=] in the [=user-agent origin=], ordered after the [=HTML user agent style sheet=].

Note: This is used to hold dynamic styles relating to transitions.

: <dfn>show view-transition root pseudo-element</dfn>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We didn't need the bool earlier because the spec ensured the lifetime of ::view-transition root pseudo-element is when this is true.

Now I see that we generate the ::view-transition pseudo-element as soon as the transition object is created.

:: A boolean. Initially false.

When this is true, [=this=]'s [=active DOM transition=]'s [=ViewTransition/transition root pseudo-element=] renders as a child of [=this=]'s [=document element=],
and [=this=]'s [=document element=] is its [=originating element=].

Note: The position of the [=ViewTransition/transition root pseudo-element=] within the [=document element=] does not matter, as the [=ViewTransition/transition root pseudo-element=]'s [=containing block=] is the [=snapshot viewport=].
</dl>

# API # {#api}
Expand Down Expand Up @@ -591,6 +615,10 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;
1. "`animating`".
1. "`done`".

Note: For the most part, a developer using this API does not need to worry about the different phases, since they progress automatically.
It is, however, important to understand what steps happen in each of the phases: when the snapshots are captured, when pseudo-element DOM is created, etc.
The description of the phases below tries to be as precise as possible, with an intent to provide an unambiguous set of steps for implementors to follow in order to produce a spec-compliant implementation.

: <dfn>DOM update callback</dfn>
:: an {{UpdateDOMCallback}} or null. Initially null.

Expand All @@ -605,6 +633,10 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;
: <dfn>finished promise</dfn>
:: a {{Promise}}.
Initially [=a new promise=] in [=this's=] [=relevant Realm=].

: <dfn>transition root pseudo-element</dfn>
:: a ''::view-transition''.
Initially a new ''::view-transition''.
</dl>

The {{ViewTransition/finished}} [=getter steps=] are to return [=this's=] [=ViewTransition/finished promise=].
Expand Down Expand Up @@ -849,13 +881,10 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

1. Set [=document/transition suppressing rendering=] to false.

1. If |transition|'s [=ViewTransition/phase=] is equal to or [=phases/after=] "`animating`",
then [=clear view transition=] |transition|.
1. [=Clear view transition=] |transition|.

1. Set |transition|'s [=ViewTransition/phase=] to "`done`".

1. Set |document|'s [=document/active DOM transition=] to null.

1. If |transition|'s [=ViewTransition/ready promise=] has not yet been resolved, [=reject=] it with |reason|.

Note: The ready promise would've been resolved if {{ViewTransition/skipTransition()}} is called after we start animating.
Expand Down Expand Up @@ -912,7 +941,7 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

1. Otherwise:

1. Render |element| and its descendants,
1. Render |element| and its [=tree/descendants=],
at the same size it appears in its [=node document=],
over an infinite transparent canvas,
following the [=capture rendering characteristics=].
Expand Down Expand Up @@ -959,9 +988,7 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

1. Let |hasActiveAnimations| be a boolean, initially false.

1. For each [=view-transition pseudo-elements=] associated with |transition|:

1. Let |element| be the [=view-transition pseudo-element=].
1. [=list/For each=] |element| of |transition|'s [=ViewTransition/transition root pseudo-element=]'s [=tree/inclusive descendants=]:

1. For each |animation| whose [=timeline=] is a [=document timeline=] associated with |document|,
and contains at least one [=animation/associated effect=] whose [=effect target=] is |element|,
Expand All @@ -981,8 +1008,6 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

1. [=Clear view transition=] |transition|.

1. Set |document|'s [=document/active DOM transition=] to null.

1. [=Resolve=] |transition|'s [=ViewTransition/finished promise=].

1. Return.
Expand Down Expand Up @@ -1020,27 +1045,24 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

1. Let |document| be [=this's=] [=relevant global object's=] [=associated document=].

1. Let |transitionRoot| be the result of creating a new ''::view-transition'' pseudo-element in |document|'s [=snapshot viewport=].
1. Set |document|'s [=show view-transition root pseudo-element=] to true.
khushalsagar marked this conversation as resolved.
Show resolved Hide resolved

1. [=map/For each=] |transitionName| → |capturedElement| of |transition|'s [=ViewTransition/named elements=]:

1. Let |group| be the result of creating a new ''::view-transition-group()'' pseudo-element with the name |transitionName|.

Issue: "name" should be defined/linked.
1. Let |group| be a new ''::view-transition-group()'',
with its [=named view-transition pseudo-element/view-transition name=] set to |transitionName|.

1. Append |group| to |transitionRoot|.
1. Append |group| to |transition|'s [=ViewTransition/transition root pseudo-element=].

Issue: This should be better defined.
I'm not sure if pseudo-elements have defined ways to modify their DOM.

1. Let |imagePair| be a new ''::view-transition-image-pair()'' pseudo-element with the name |transitionName|.
1. Let |imagePair| be a new ''::view-transition-image-pair()'',
with its [=named view-transition pseudo-element/view-transition name=] set to |transitionName|.

1. Append |imagePair| to |group|.

1. If |capturedElement|'s [=captured element/old image=] is not null, then:

1. Let |old| be a new ''::view-transition-old()'' [=replaced element=] pseudo-element,
with the name |transitionName|,
1. Let |old| be a new ''::view-transition-old()'',
with its [=named view-transition pseudo-element/view-transition name=] set to |transitionName|,
displaying |capturedElement|'s [=captured element/old image=].

1. Append |old| to |imagePair|.
Expand All @@ -1061,15 +1083,15 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

1. If |capturedElement|'s [=new element=] is not null, then:

1. Let |new| be a new ''::view-transition-new()'' [=replaced element=] pseudo-element,
with the name |transitionName|,
1. Let |new| be a new ''::view-transition-new()'',
with its [=named view-transition pseudo-element/view-transition name=] set to |transitionName|,
displaying the [=capture the image=] of |capturedElement|'s [=new element=].

1. Append |new| to |imagePair|.

The [=new element=] and its contents
(the flat tree descendants of the element, including both text and elements, or the replaced content of a replaced element),
except the [=view-transition pseudo-elements=],
except the |transition|'s [=ViewTransition/transition root pseudo-element=]'s [=tree/inclusive descendants=],
are not painted (as if they had visibility: hidden)
and do not respond to hit-testing (as if they had pointer-events: none) until |new| exists.

Expand Down Expand Up @@ -1250,18 +1272,19 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

1. Let |document| be |transition|'s [=relevant global object's=] [=associated document=].

1. Remove all associated [=view-transition pseudo-elements=] from |document|.

Issue: There needs to be a definition/link for "remove".

Issue: There needs to be a definition/link for "associated".
1. [=Assert=]: |document|'s [=document/active DOM transition=] is |transition|.

1. [=list/For each=] |capturedElement| of |transition|'s [=ViewTransition/named elements=]' [=map/values=]:

1. [=list/For each=] |style| of |capturedElement|'s [=captured element/style definitions=]:

1. If |style| is not null,
and |style| is in |document|'s [=document/view transition style sheet=],
then remove |style| from |document|'s [=document/view transition style sheet=].

1. Set |document|'s [=document/show view-transition root pseudo-element=] to false.

1. Set |document|'s [=document/active DOM transition=] to null.
khushalsagar marked this conversation as resolved.
Show resolved Hide resolved
</div>

<h2 id="priv" class="no-num">Privacy Considerations</h2>
Expand Down