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

[selectors-4] Absolutizing relative selectors against a virtual scoping root is weird and broken #2199

Open
fantasai opened this Issue Jan 18, 2018 · 2 comments

Comments

Projects
None yet
4 participants
@fantasai
Contributor

fantasai commented Jan 18, 2018

Current spec prose:

If there are no :scope elements and the selector is scoped to a virtual scoping root:

  1. If the selector starts with a child combinator, remove the child combinator. The selector is now absolute, with the additional constraint that the first compound selector in the selector only matches elements without a parent.
  2. Otherwise, if the selector starts with any combinator other than the white space form of the descendant combinator, change the selector to :not(*). This is the shortest selector that is valid, but guaranteed to match nothing.
  3. Otherwise, the selector is already absolute.

There are three problems, corresponding to each point:

  1. The resulting “absolute” selector is carrying out-of-band information. The point of absolutizing something is to incorporate contextual information into the thing itself. At least before we remove the combinator in > foo, it's clear that it's not representing the same thing as foo.
  2. :not(*) is guaranteed to match nothing only if it's not in a negated context. If it's negated, then we match everything. So this is not a good way to represent a selector that matches nothing.
  3. Currently foo as a relative selector with a non-virtual scoping root is absolutized to :scope foo. Since we don't consider it acceptable for absolutizing foo as foo in that case, then how is leaving foo as foo here considered acceptable? Either both cases need some kind of transformation, or neither of them does.

Also, in every other case, an author writing out an explicit :scope, e.g. :scope > foo gets the same result as as an implied one, e.g. > foo; we are breaking that pattern here.

Possible ways forward:

  • Give up on the concept of “absolutizing” a selector and define matching against relative selectors as its own special thing.
  • Define :scope as matching against virtual scoping roots and let relative selectors absolutize the same regardless of the root type. (We already have a concept of “featureless” elements, we just define it as “featureless” and that a selector with it as the subject returns nothing.) Relative selectors then return to being syntactic sugar for a prefixed :scope.

I'm mostly in favor of the latter, since it seems simpler conceptually, as well as more author-friendly. There might be other solutions, but the current text is problematic imho.

@tabatkins

This comment has been minimized.

Member

tabatkins commented Jan 18, 2018

The point of absolutizing something is to incorporate contextual information into the thing itself.

No, the point of absolutizing something is to make it an absolute value, rather than being relative to something else. That's what the current spec text does. The fact that absolutizing such a selector produces something that can't be perfectly reproduced in a literal form is slightly inconvenient but irrelevant. (Had we decided the other way with :root to make it match anything without a parent, or had decided to accept :top-level, then it could be represented in a literal form. But the fact that it can't currently isn't relevant here.)

:not(*) is guaranteed to match nothing only if it's not in a negated context. If it's negated, then we match everything. So this is not a good way to represent a selector that matches nothing.

That's... fine? The point is that docFrag.query("+ div") can't match anything - nothing is the sibling of a document fragment. If this somehow gets negated (how?), then you're asking for "everything that's not an immediate sibling of the document fragment", and that is indeed every reachable element.

Currently foo as a relative selector with a non-virtual scoping root is absolutized to :scope foo. Since we don't consider it acceptable for absolutizing foo as foo in that case, then how is leaving foo as foo here considered acceptable? Either both cases need some kind of transformation, or neither of them does.

No, it's working exactly correctly here. Again, docFrag.query("div") returns exactly the same elements whether you interpret it as a relative or absolute selector; all the div elements inside the fragment are descendants of the fragment.

This is different from a non-virtual scoping root, which exists in a document with other elements outside of it, which could potentially be (incorrectly) matched by just treating the selector as absolute. Thus why you need to add :scope there, to correctly pipe in the knowledge that the matched elements must have the scoping element as their ancestor.


Give up on the concept of “absolutizing” a selector and define matching against relative selectors as its own special thing.

Possible but unnecessary - none of the "problems" you listed above are actually problems.

Define :scope as matching against virtual scoping roots [...]

We could do this. The concept of an invisible featureless parent element didn't exist when I first wrote this text; the Shadow DOM stuff came later. Going this way would let us entirely remove this section and just rely on the standard scoping-root stuff, which is probably a good idea.

@therealglazou

This comment has been minimized.

Contributor

therealglazou commented Jan 30, 2018

We could do this. The concept of an invisible featureless parent element didn't exist when I first wrote this text; the Shadow DOM stuff came later. Going this way would let us entirely remove this section and just rely on the standard scoping-root stuff, which is probably a good idea.

I think it's not only a good idea but a better idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment