Skip to content

[css-selectors-5] Proposal: :capture() and :group() functional pseudo-classes #13368

@rokke-git

Description

@rokke-git

The purpose of this pair of functions is to allow capture and re-use of specific identifiers within a selector-list. After writing this, I also found previous, closely related discussion in #10567.

:capture() is a functional pseudo-class taking a modified complex-selector as an argument. In place of any identifier, an asterisk may be used to capture values. :capture() restricts the matches of a selector in the same way the provided complex-selector argument would, ignoring any identifiers replaced with an asterisk. For example, h1:capture(#*.cls) would match the same elements as h1.cls.

:group() is a corresponding functional pseudo-class taking a list of integer number-tokens, and appears in the same selector-list as at least one :capture(). The numbers refer to :capture() classes in the order that they appear. :group() restricts the selector by the elements which the referent capture would match. For example, table:capture(.*:hover) :group(1) would match any descendants of a table with :hover, where the descendants also share a class with an element with :hover.

To expand on this example, say a document has exactly 5 classes: cls1, cls2, cls3, cls4, cls5.
table:capture(.*:hover) td:group(1) could then be equivalently written:

:root:has(.cls1:hover) table:hover td.cls1,
:root:has(.cls2:hover) table:hover td.cls2,
:root:has(.cls3:hover) table:hover td.cls3,
:root:has(.cls4:hover) table:hover td.cls4,
:root:has(.cls5:hover) table:hover td.cls5

note how this is different from:

:root:has(.cls1:hover, .cls2:hover, .cls3:hover, .cls4:hover, .cls5:hover)
    table:hover
        td:is(.cls1, .cls2, .cls3, .cls4, .cls5)

example


The argument to :capture() may include multiple asterisks. In this case, the corresponding :group() must match at least one identifier from each asterisk. For example, say :capture(*.*#id1) captures div, h1, and cls1, cls2, cls3. The corresponding :group(1) will now restrict matches to one of div.cls1, div.cls2, div.cls3, h1.cls1, h1.cls2, and h1.cls3. Each application must also be unique, for example :capture(*.*.*#id1) with the same captures would give a :group(1) with restricts things to div.cls1.cls2, div.cls1.cls3, div.cls2.cls3, h1.cls1.cls2, h1.cls1.cls3, and h1.cls2.cls3.

There may be multiple numeric arguments to :group(). In this case, only one group must match. For example, say :capture(*#id1):capture(.*#id2) captures div, h1, h2, and cls1, cls2. The corresponding :group(1, 2) will now restrict matches to any of div, h1, h2, .cls1, or .cls2; this means a.cls2 and div.cls5 both match.

:group() may come before the :capture() it references in a selector list, but the complex selector in :capture() may not contain any :group() calls. If a :capture() appears inside a :capture(), the outer :capture() retains asterisks from the inner one. For example, :capture(*:capture(.*#id1)) would result in a :group(1) which matches :capture(*.*#id1) and a :group(2) which matches :capture(.*#id1).

:capture() may capture any identifier in the complex-selector.

  • namespace: *|
  • type: *
  • id: #*
  • class: .*
  • attribute: [*]
  • value: [foo=*]
  • attribute with a value: [*="foo"], [*|="foo" s], [*$="foo" i], [**="foo"], etc.
  • pseudo-classes (non-function ones): :*
  • pseudo-elements: ::*

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions