Skip to content

Commit

Permalink
[selectors-4] Untangle 'scoped' from 'relative'. #6399
Browse files Browse the repository at this point in the history
  • Loading branch information
tabatkins committed Jun 2, 2022
1 parent 617c50c commit f6337dd
Showing 1 changed file with 74 additions and 134 deletions.
208 changes: 74 additions & 134 deletions selectors-4/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ Selectors Overview</h2>
<tr>
<td><code>E:has(<var>rs1</var>, <var>rs2</var>, &hellip;)</code>
<td>an E element,
if either of the <a>relative selectors</a> <var>rs1</var> or <var>rs2</var>,
when evaluated with E as the <a>:scope elements</a>,
match an element
if there exists an element that matches
either of the <a>relative selectors</a> <var>rs1</var> or <var>rs2</var>,
when evaluated with E as the <a>anchor elements</a>
<td>[[#relational]]
<td>4
<tbody>
Expand Down Expand Up @@ -272,7 +272,7 @@ Selectors Overview</h2>
<td>4
<tr>
<td><code>E:scope</code>
<td>an E element being a designated reference element
<td>an E element being a [=scoping root=]
<td>[[#the-scope-pseudo]]
<td>4
<tbody>
Expand Down Expand Up @@ -502,7 +502,7 @@ Structure and Terminology</h3>
a particular pattern of element(s) in a tree structure.
The term <a>selector</a> can refer to a <a>simple selector</a>,
<a>compound selector</a>, <a>complex selector</a>, or <a>selector list</a>.
The <dfn export for=selector lt="subject|subject of a selector">subject of a selector</dfn> is
The <dfn export for=selector lt="subject|subject of a selector|subject of the selector">subject of a selector</dfn> is
any element that selector is defined to be about;
that is, any element <dfn export lt="match">matching</dfn> that <a>selector</a>.

Expand Down Expand Up @@ -636,10 +636,8 @@ Data Model</h3>
Scoped Selectors</h3>

Some host applications may choose to <dfn export lt="scoped selector" local-lt="scope">scope</dfn> selectors
to a particular subtree or fragment of the document.
The root of the scoping subtree is called the <dfn export>scoping root</dfn>,
and may be either a true element (the <dfn export>scoping element</dfn>)
or a <dfn export lt="virtual scoping root">virtual</dfn> one (such as a <a interface>DocumentFragment</a>).
to a particular subtree or fragment of the document,
The root of the scoping subtree is called the <dfn export>scoping root</dfn>.

When a selector is <a>scoped</a>,
it matches an element only if the element is a descendant of the <a>scoping root</a>.
Expand All @@ -648,83 +646,31 @@ Scoped Selectors</h3>

<div class='example'>
For example,
the <code>element.querySelector()</code> function defined in [[DOM]]
the {{Element/querySelector()}} method defined in [[DOM]]
allows the author to evaluate a <a>scoped</a> selector
relative to the <code>element</code> it's called on.
relative to the element it's called on.

A call like <code highlight=js>widget.querySelector("a")</code>
will thus only find <{a}> elements inside of the <code>widget</code> element,
ignoring any other <{a}>s that might be scattered throughout the document.
</div>

Note: If the context does not explicitly define any <a>:scope elements</a> for the selector,
the <a>scoping root</a> is the <a>:scope element</a>.

<h3 id="relative">
Relative Selectors</h3>

Certain contexts may accept <dfn lt="relative selector | relative | scope-relative" export>relative selectors</dfn>,
which are a shorthand for selectors that represent elements relative to a <a>:scope element</a>
(i.e. an element that matches '':scope'').
In a <a>relative selector</a>,
“:scope ” (the '':scope'' pseudo-class followed by a space)
is implied at the beginning of each <a>complex selector</a>
that does not already contain the '':scope'' pseudo-class.
This allows the selector to begin syntactically with a <a>combinator</a>.
However, it must be <a href="#absolutize">absolutized</a> before matching.
Certain contexts may accept <dfn lt="relative selector" local-lt="relative" export>relative selectors</dfn>,
which are a shorthand for selectors that represent elements relative to one or more
<dfn export local-lt="anchor element">relative selector anchor elements</dfn>.
Relative selectors begin with a <a>combinator</a>,
with a selector representing the [=anchor element=]
implied at the start of the selector.
(If no combinator is present,
the [=descendant combinator=] is implied.)

Relative selectors, once absolutized,
can additionally be <a>scoped</a>.
Relative selectors are represented by <<relative-selector>> in the selectors <a href="#grammar">grammar</a>,
and lists of them by <<relative-selector-list>>.

Relative selectors are represented by <<relative-selector>> in the selectors <a href="#grammar">grammar</a>.

<h4 id='absolutizing'>
Absolutizing a Relative Selector</h4>

To <dfn id='absolutize' export>absolutize a relative selector</dfn>:

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

ISSUE: <a href="https://github.com/w3c/csswg-drafts/issues/2199">This needs a sane definition.</a>

<!--
<ol>
<li>
If the selector starts with a <a>child combinator</a>,
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.
<li>
Otherwise, if the selector starts with any combinator other than the white space form of the <a>descendant combinator</a>,
change the selector to '':not(*)''.
<span class='note'>This is the shortest selector that is valid, but guaranteed to match nothing.</span>
<li>
Otherwise, the selector is already absolute.
</ol>
-->

Otherwise:

<ol>
<li>
If the selector starts with a <a>combinator</a> other than the white space form of the <a>descendant combinator</a>,
prepend '':scope'' as the initial <a>compound selector</a>.

<li>
Otherwise, if the selector does not contain any instance of the '':scope'' pseudo-class
(either at the top-level or as an argument to a functional pseudo-class),
prepend '':scope'' followed by the white space form of the <a>descendant combinator</a>.

<li>
Otherwise, the selector is already absolute.
</ol>

To <dfn id='absolutize-list' export>absolutize a relative selector list</dfn>,
absolutize each relative selector in the list.


<h3 id="pseudo-classes">
Expand Down Expand Up @@ -1244,10 +1190,9 @@ The Relational Pseudo-class: '':has()''</h3>

The relational pseudo-class, <dfn id='has-pseudo'>:has()</dfn>,
is a functional pseudo-class taking a <<forgiving-relative-selector-list>> as an argument.
It represents an element if any of the <a>relative selectors</a>,
when <a href="#absolutize">absolutized</a>
and evaluated with the element as the <a>:scope elements</a>,
would match at least one element.
It represents an element if any of the <a>relative selectors</a>
would match at least one element
when [=anchor element|anchored against=] this element.

<div class='example'>
For example, the following selector matches only
Expand All @@ -1274,8 +1219,6 @@ The Relational Pseudo-class: '':has()''</h3>
which contains anything that's not a heading element.
</div>

Supporting the '':has()'' pseudo-class is not required to conform to this specification.


<h2 id="elemental-selectors">
Elemental selectors</h2>
Expand Down Expand Up @@ -2159,20 +2102,37 @@ The Target Container Pseudo-class: '':target-within''</h3>
<h3 id="the-scope-pseudo">
The Reference Element Pseudo-class: '':scope''</h3>

In some contexts, selectors can be matched with an explicit set of <dfn dfn export lt=":scope element">:scope elements</dfn>.
This is a (potentially empty) set of elements
that provide a reference point for selectors to match against,
such as that specified by the <code>querySelector()</code> call in [[DOM]].
In some contexts, selectors are matched
with respect to one or more [=scoping roots=],
such as when calling the {{Element/querySelector()}} method in [[DOM]].
The <dfn id='scope-pseudo'>:scope</dfn> pseudo-class represents
this [=scoping root=],
and may be either a true element
or a virtual one (such as a {{DocumentFragment}}).

The <dfn id='scope-pseudo'>:scope</dfn> pseudo-class represents any element that is a <a>:scope element</a>.
If the <a>:scope elements</a> are not explicitly specified,
but the selector is <a>scoped</a> and the <a>scoping root</a> is an element,
then '':scope'' represents the <a>scoping root</a>;
otherwise, it represents the root of the document
If there is no [=scoping root=]
then '':scope'' represents the root of the document
(equivalent to '':root'').
Specifications intending for this pseudo-class to match specific elements
rather than the document's root element
must define either a <a>scoping root</a> (if using <a>scoped selectors</a>) or an explicit set of <a>:scope elements</a>.
must define their [=scoping root|scoping root(s)=].

A virtual [=scoping root=] is some object representing the root of a document fragment,
and can be used in selector patterns to represent other elements’ relationships
to this [=scoping root=],
acting as the parent of any root elements in the document fragment it represents.
A virtual [=scoping root=] is [=featureless=]
and cannot be the [=subject of the selector=].

<div class=example>
For example, if you have a {{DocumentFragment}} <code>df</code>,
then <code highlight=js>df.querySelectorAll(":scope > .foo")</code>
matches all the ''.foo'' elements that are "top-level" in the document fragment
(those that have the document fragment as their {{Node/parentNode}}).

However, <code highlight=js>df.querySelector(":scope")</code> will not match anything,
as the document fragment itself can't be the [=subject of the selector=].
</div>

<h2 id="useraction-pseudos">
User Action Pseudo-classes</h2>
Expand Down Expand Up @@ -3678,30 +3638,25 @@ Parse A Selector</h3>
<h3 id='parse-relative-selector' algorithm>
Parse A Relative Selector</h3>

This section defines how to <dfn export>parse a relative selector</dfn> from a string <var>source</var>,
against <a>:scope elements</a> <var>refs</var>.
This section defines how to <dfn export>parse a relative selector</dfn> from a string <var>source</var>.
It returns either a complex selector list,
or failure.

<ol>
<li>
Let <var>selector</var> be the result of [=CSS/parsing=] <var>source</var> as a <<relative-selector-list>>.
If this return failure,
If this returns failure,
it's an [=invalid selector=];
return failure.

<li>
Otherwise,
if any simple selectors in <var>selector</var> are not recognized by the user agent,
or <var>selector</var> is otherwise invalid in some way
If |selector| is an [=invalid selector=] for any other reason
(such as, for example, containing an undeclared namespace prefix),
return failure.

<li>
Otherwise,
<a lt="absolutize a relative selector list">absolutize <var>selector</var></a> with <var>refs</var> as the <a>:scope elements</a>.

<li>
Return <var>selector</var>.
return <var>selector</var>.
</ol>

<h3 id='match-against-element' algorithm>
Expand All @@ -3715,16 +3670,8 @@ Match a Selector Against an Element</h3>

<ul>
<li>
a set of <a>:scope elements</a>,
one or more [=scoping roots=],
for resolving the '':scope'' pseudo-class against.
If not specified,
the set defaults to being empty.

Issue: Should it instead default to the root element,
to match the definition of '':scope''?

If the selector is a <a>relative selector</a>,
the set of <a>:scope elements</a> must not be empty.
</ul>

This algorithm returns either success or failure.
Expand Down Expand Up @@ -3794,47 +3741,28 @@ Match a Selector Against a Tree</h3>

APIs using this algorithm must provide a selector,
and one or more <var>root elements</var>
indicating the <a>trees</a> that will be searched by the selector.
All of the <var>root elements</var> must share the same <a for=tree>root</a>,
indicating the [=tree|subtrees=] that will be searched by the selector.
All of the <var>root elements</var> must share the same [=tree/root=],
or else calling this algorithm is invalid.

They may optionally provide:

<ul>
<li>
A <a>scoping root</a>
One or more <a>scoping roots</a>
indicating the selector is <a>scoped</a>.
If not specified,
the <var>selector</var> defaults to being unscoped.

Issue: This is now redundant with the <var>root elements</var>.

<li>
A set of <a>:scope elements</a>,
which will match the '':scope'' pseudo-class.
If not specified,
then if the selector is a <a>scoped selector</a>,
the set of <a>:scope elements</a> default to the <a>scoping root</a>;
otherwise,
it defaults to the <var>root elements</var>.

Note: Note that if the selector is scoped,
the scoping root is automatically taken as the <a>:scope element</a>,
so it doesn't have to be provided explicitly
unless a different result is desired.

<li>
Which <a>pseudo-elements</a> are allowed to show up in the match list.
A list of <a>pseudo-elements</a> that are allowed to show up in the match list.
If not specified, this defaults to allowing all pseudo-elements.

Issue: Only the ''::before'' and ''::after'' pseudo-elements are really
Issue: Only the [=tree-abiding pseudo-elements=] are really
handled in any way remotely like this.
</ul>

This algorithm returns a (possibly empty) list of elements.

<ol>

<li>
Start with a list of <var>candidate elements</var>,
which are the <var>root elements</var>
Expand All @@ -3843,10 +3771,10 @@ Match a Selector Against a Tree</h3>
unless otherwise specified.

<li>
If an optional scoping root was provided,
If [=scoping root=] were provided,
then remove from the <var>candidate elements</var>
any elements that are not
<a>descendants</a> of the <a>scoping root</a>.
<a>descendants</a> of at least one <a>scoping root</a>.

<li>
Initialize the <var>selector match list</var> to empty.
Expand Down Expand Up @@ -4057,6 +3985,18 @@ Appendix B: Obsolete but Required Parsing Quirks for Web Compat</h2>

<h2 id="changes">
Changes</h2>

<h3 id="changes-2022-05">
Changes since the 7 May 2022 Working Draft</h3>

Significant changes since the <a href="https://www.w3.org/TR/2022/WD-selectors-4-20220507/">7 May 2022 Working Draft</a>:

* Untangled the concepts of "scoped" and "relative" selectors completely.
(<a href="https://github.com/w3c/csswg-drafts/issues/6399">Issue 6399</a>)
* Removed "absolutize a selector" as well,
and just defined relative selector matching
in terms of the anchoring element.

<h3 id="changes-2018-11">
Changes since the 21 November 2018 Working Draft</h3>

Expand Down

0 comments on commit f6337dd

Please sign in to comment.