w3c / w3c/csswg-drafts

[selectors] New universal selector including tree-abiding pseudo-elements

Open
#4,565 4 comments 4 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

selectors-4 selectors-5
Dominant language
Bikeshed
Stars
4.9k
Forks
816
PR merge metrics
PR metrics pending

Description

The universal selector * is not actually that universal, since it only selects elements, but not pseudo-elements.

This can be annoying. For example, some authors prefer the border-box sizing model and want to use it everywhere by default. Then they need something like

*, ::before, ::after { box-sizing: border-box }

Another example is ::marker. Someone may want to assign some styles to all markers, but ::marker alone only selects markers originated by elements, not by other pseudo-elements. So actually they will need

::marker, ::before::marker, ::after::marker { ... }

This may be easy to forget. Even the spec editors did! #4474

Also, currently ::marker is very restricted but in the future it may support arbitrary properties. So the 1st example may become

*, ::before, ::after, ::marker, ::before::marker, ::after::marker {
  box-sizing: border-box;
}

To avoid this nonsense, I propose adding a new kind of universal selector that also selects tree-abiding pseudo-elements. I don't care about the syntax, but let's say e.g. **.

Then, ** { box-sizing: border-box } would switch everything to the border-box sizing model.

And **::marker would select all markers.

Since this selector can select pseudo-elements, it should be restricted. It can only be used at the end of a complex selector, or immediately before a pseudo-element or a pseudo-class that is allowed after some tree-abiding pseudo-element. For example,

  • foo#bar > .baz ** is valid.
  • **::marker is valid because ::before::marker is valid, even if ::marker::marker is invalid.
  • ** ::marker is invalid since there is a descendant combinator.
  • **::before is invalid since ::before can't appear after another pseudo-element. Alternatively, it could be a synonym of *::before.
  • **:hover is valid because ::before:hover is valid
  • **:root is invalid since :root can't appear after a pseudo-element. Alternatively, it could be a synonym of *:root.

Also, until #2284 is resolved, ** shouldn't be allowed inside functions either. For example, :is(**) is invalid.

I'm not that sure if ** should be allowed at the end of a compound selector after simple selectors, e.g.

  • #foo** could be #foo, #foo::before, #foo::before::marker, ...
  • ::slotted(.bar)** could be ::slotted(.bar), ::slotted(.bar)::before, ...

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the Selectors Level 4 universal selector and CSS Pseudo-4 tree-abiding pseudo-elements sections referenced in the issue. Review related issues #4474 and #2284 before deciding the selector syntax and restrictions; done means the CSS specifications define and consistently resolve the proposed universal pseudo-element selection behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
css
Domain
frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.