Skip to content

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

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

Merged
merged 13 commits into from
Jan 12, 2023

Conversation

jakearchibald
Copy link
Contributor

@jakearchibald jakearchibald commented Nov 22, 2022

This attempts to define how pseudos are built and ordered. It also defines the view-transition-name of the pseudos.

Fixes #8113.

@@ -197,38 +197,59 @@ 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.

Copy link
Member

@vmpstr vmpstr left a comment

Choose a reason for hiding this comment

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

Generally looks good. I'm starting to get a bit worried that this is extremely complicated to read, but that's not due to this PR: it has been building up.

I'll read the spec once its compiled again, but perhaps we can have separate "intro" sections for pseudo element algorithms that just describe the tree and a separate "intro" section for the startViewTransition process and steps that follow. WDYT?


Note: For example, '':root::view-transition'' selector matches this pseudo-element,
but ''div::view-transition'' does not.
A [=pseudo-element parent=]'s [=pseudo-element parent/children=] are laid out in the order they appear in the [=/list=], according to their styles.
Copy link
Member

Choose a reason for hiding this comment

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

Is this an important point? "according to their styles" seems to imply that they are laid out in some way that is determined by the layout system, but that also seems to be the unspoken default for every element. I'm also unsure if "layout" is defined anywhere; I am only aware of Update the Rendering steps

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I want to communicate that the order in the list matters. I started with "render in the order they appear in the list", but CSS can change render order, so I wanted to be clear that still counts.

How about "the order of items in the list represents the document order of the pseudo-elements"?

Copy link
Member

Choose a reason for hiding this comment

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

I'm worried we'll end up re-defining a lot of DOM concepts if we have to define how a tree of pseudo-elements works. For instance, this still leaves hit-testing in an ambiguous state.

Also, implementation wise a pseudo-element tree works exactly like a node tree. I mean if you inserted nodes using the script API in the same order (as defined in this spec), style, layout, paint, hit-testing would all work the same as a script generated DOM tree. The only difference here is that the Node APIs are not exposed to the developer.

So could we just clarify the difference between pseudo-element and node, and then lean on same spec concepts as a node tree for this pseudo-element tree?

Copy link
Contributor Author

@jakearchibald jakearchibald Nov 23, 2022

Choose a reason for hiding this comment

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

So could we just clarify the difference between pseudo-element and node

I don't think that should be this spec's job.

The additions we need compared to ::before and ::after:

  • A clear tree structure. Although ::before::marker already has nesting, it's hand-waved in a way that I don't think it suitable for the level of nesting we have.
  • Insert and remove. ::before and ::after are kinda 'always there', whereas ours come and go.
  • Ordering within the parent. ::before and ::after hand-wave this in a kinda ambiguous way.

My intent here is that [=pseudo-element parent=]'s [=pseudo-element parent/children=] defines that the pseudos are document children of the parent, in that order.

I don't think we need to define hit testing, because (I assume) the hit testing of pseudo-elements is already defined, and it would be redundant to say that these pseudo-elements behave like pseudo-elements.

one for each 'view-transition-name' participating in a transition.
<div algorithm>
To get the <dfn for="pseudo-element parent">descendants</dfn> of a [=pseudo-element parent=] |parent|, perform the following steps.
They return a [=/list=] of [=pseudo-elements=].
Copy link
Member

Choose a reason for hiding this comment

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

I don't think you need this line

Copy link
Contributor Author

Choose a reason for hiding this comment

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


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=].
A <dfn>pseudo-element parent</dfn> is a mixin that has <dfn for="pseudo-element parent">children</dfn>,
Copy link
Member

Choose a reason for hiding this comment

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

What does mixin mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, I was hoping https://en.wikipedia.org/wiki/Mixin was well-understood. Is there a term that's more familiar? "Trait"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could change it to "If something is a pseudo-element parent, it has…", which avoids "mixin"


Note: For example, '':root::view-transition'' selector matches this pseudo-element,
but ''div::view-transition'' does not.
A [=pseudo-element parent=]'s [=pseudo-element parent/children=] are laid out in the order they appear in the [=/list=], according to their styles.
Copy link
Member

Choose a reason for hiding this comment

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

I'm worried we'll end up re-defining a lot of DOM concepts if we have to define how a tree of pseudo-elements works. For instance, this still leaves hit-testing in an ambiguous state.

Also, implementation wise a pseudo-element tree works exactly like a node tree. I mean if you inserted nodes using the script API in the same order (as defined in this spec), style, layout, paint, hit-testing would all work the same as a script generated DOM tree. The only difference here is that the Node APIs are not exposed to the developer.

So could we just clarify the difference between pseudo-element and node, and then lean on same spec concepts as a node tree for this pseudo-element tree?

@@ -371,6 +397,8 @@ urlPrefix: https://html.spec.whatwg.org/multipage/rendering.html; type: dfn;

This means the snapshot canvas size is likely to be consistent for the [=document element=]'s [=captured element/old image=] and [=captured element/new element=].

The [=snapshot viewport=] is also a [=pseudo-element parent=].
Copy link
Member

Choose a reason for hiding this comment

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

I didn't follow this. The snapshot viewport is just a conceptual containing block, not a pseudo-element.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I was unsure about this too. Any feelings on the right terms to use here? When we add a ::view-transition, what are we adding it to?

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|.

If a [=pseudo-element parent=]'s [=pseudo-element parent/children=]'s [=list/size=] is 1, then '':only-child'' selects [=pseudo-element parent/children=][0].
Copy link
Member

Choose a reason for hiding this comment

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

How should only-child work for ::view-transitions whose originating element is html. If we consider ::view-transition to be a child, similar to other DOM children, then should it always match? I can't think of a case where there are no nodes under html. Even if its possible, it'll be simpler if we don't have to support that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are you referring to ::view-transition:only-child? By this definition it wouldn't match, since it isn't in a [=pseudo-element parent=].

It doesn't seem useful to do ::view-transition:only-child, so I don't mind saying it always matches, or never matches.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The more I think about it, I think ::view-transition:only-child should be 'invalid'.

element:only-child ignores pseudo-elements, so I don't think there's a sensible behaviour for ::pseudo:only-child when the pseudo is a child of an element.

Copy link
Member

Choose a reason for hiding this comment

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

element:only-child ignores pseudo-elements, so I don't think there's a sensible behaviour for ::pseudo:only-child when the pseudo is a child of an element.

That makes sense. And lines up with @vmpstr's suggestion + the implementation.

- 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=].
- The [=view-transition layer=]'s [=containing block=] is the [=snapshot viewport=].
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
- The [=view-transition layer=]'s [=containing block=] is the [=snapshot viewport=].
- The [=containing block=] of this pseudo-element is the [=snapshot viewport=].

And move this to the definition for ::view-transition.

@@ -1020,30 +1054,27 @@ 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. [=list/Append=] |transition|'s [=ViewTransition/transition root pseudo-element=] to this |document|'s [=snapshot viewport=]'s [=pseudo-element parent/children=].
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
1. [=list/Append=] |transition|'s [=ViewTransition/transition root pseudo-element=] to this |document|'s [=snapshot viewport=]'s [=pseudo-element parent/children=].
1. [=list/Append=] |transition|'s [=ViewTransition/transition root pseudo-element=] to this |document|'s root element.

Because snapshot viewport is just a conceptual containing block (not a node), like layout viewport.

Copy link
Contributor Author

@jakearchibald jakearchibald Nov 24, 2022

Choose a reason for hiding this comment

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

Ugh, I totally forgot about this. Still leaves us with a hand-wave. Ok, I've got a plan.

Reminder for me: Define something on document element for this pseudo to go.


Issue: There needs to be a definition/link for "associated".
1. [=list/Remove=] |transition|'s [=ViewTransition/transition root pseudo-element=]
from |document|'s [=snapshot viewport=]'s [=pseudo-element parent/children=].
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
from |document|'s [=snapshot viewport=]'s [=pseudo-element parent/children=].
from |document|'s root element.

When this is a ''::view-transition'', the ''::view-transition'' renders as a child of the [=document element=],
and the [=document element=] is its [=originating element=].

Note: The position of the ''::view-transition'' within the [=document element=] does not matter, as the ''::view-transition'''s [=containing block=] is the [=snapshot viewport=].
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@khushalsagar is this a correct statement?

Copy link
Member

Choose a reason for hiding this comment

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

A [=document element=] additionally has a view-transition root pseudo-element.
A ''::view-transition'' or null. Initially null.
When this is a ''::view-transition'', the ''::view-transition'' renders as a child of the [=document element=],
and the [=document element=] is its [=originating element=].

Do we need all this text? I figured its enough to say: [=document element=] is the [=originating element=] for ''::view-transition'' and ''::view-transition'''s [=containing block=] is the [=snapshot viewport=].

What we do need is spec text to say:

  • ''::view-transition'' is not clipped by [=document element=].
  • Effects on the [=document element=] do not apply to ''::view-transition''.

There is similar spec text for this for top layer elements here.

''::view-transition'' renders as a child of the [=document element=] makes it sound like its the opposite of the above 2 points.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I want a thing that can be ::view-transition or null, so when it's not null, it's rendered, and when it's null, it's not rendered. As in, a way to say when it's in the document or not.

So… what is it 'in' when it's there?


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 ''::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=].
Issue: This definition should be moved to [[css-pseudo-4]].
Copy link
Member

Choose a reason for hiding this comment

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

nit: I asked for doing this in the pseudo spec earlier. But based on fantasai's comment here: #8113 (comment), the definition can stay in this spec until another feature needs it to be generalized. So do we need the issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair. I'll turn it into a note.


Its [=originating element=] is the ''::view-transition'' pseudo-element.
It is selected from its [=ultimate originating element=], the [=document element=].
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).

@@ -466,6 +486,13 @@ 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>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.

nit: Do we need this here? We should be able to refer to this by active DOM transition's transition root pseudo-element.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a very good point. In fact, it's kinda silly that this isn't cleared as part of "Clear view transition". I'll fix that up.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, now I know why.

We don't add the "view-transition root pseudo-element" at the same time as the active transition. The document's "view-transition root pseudo-element" is used to define when this pseudo element is in the document.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll change it to a boolean to avoid duplicated info

Also clean up the use of phases, and put the note in the correct place
@@ -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.

@khushalsagar khushalsagar merged commit b7fc74a into w3c:main Jan 12, 2023
@jakearchibald jakearchibald deleted the parent-pseudos branch January 12, 2023 16:46
jakearchibald added a commit to jakearchibald/csswg-drafts that referenced this pull request Jan 16, 2023
* Define pseudo-nesting and naming

* Language tweak

* Specify tree-abiding

* Tidy up pseudo-parent definition

* Define :only-child behaviour

* Nit

* Clarify snapshot viewport as containing block

* Define adding the ::view-transition

* Move iew-transition root pseudo-element to document

* Base on tree terminology

* Change issue to note

* Make "show view-transition root pseudo-element" a boolean

Also clean up the use of phases, and put the note in the correct place

* Set show pseudo to false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[css-view-transitions-1] Prose to modify pseudo-trees
4 participants