Skip to content
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] New universal selector including tree-abiding pseudo-elements #4565

Open
Loirooriol opened this issue Dec 6, 2019 · 4 comments
Labels

Comments

@Loirooriol
Copy link
Contributor

Loirooriol commented Dec 6, 2019

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, ...
@ExE-Boss
Copy link
Contributor

Alternatively, ::* could be used to mean the same thing.

@tabatkins
Copy link
Member

The use-case here seems pretty valid. I much prefer the ::* suggestion from @ExE-Boss; it keeps the overall structure of the selector (the fact that you are definitely selecting into the pseudo-tree) more obvious. The only potentially tricky bit is that it can select multiple pseudo-levels in, but that's fine I think.

(That is intended, right? So ::*:hover matches both ::before:hover and ::before::marker:hover?)

This also makes your "invalid" cases clearer - ::*:root is more clearly invalid, since you're trying to apply :root to an (unnamed) pseudo-element.

@Loirooriol
Copy link
Contributor Author

I already thought about ::*. The problem is that it seems to me that the main use case is being able to select both elements and full-fledged element-like pseudo-elements. But ::* seems to only select pseudo-elements, not elements. And it seems to select all pseudo-elements, which could be a forwards compatibility concern when adding new pseudo-elements; restricting the selector to tree-abiding pseudo-elements could be safer. Also, IMO ::* looks like it's only selecting direct pseudo-elements, not nested ones.

So I'm not that convinced about ::*. But I guess it could do the trick after addressing #2284, so that we can use something like #foo > .bar + baz:is(*, ::*).

@fantasai
Copy link
Collaborator

fantasai commented Nov 8, 2022

+1 to @Loirooriol’s comment. ::* looks like it selects all pseudo-elements, and I think you basically never want to do that.

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

No branches or pull requests

4 participants