postcss / postcss-selector-matches

PostCSS plugin to transform :matches() W3C CSS pseudo class to more compatible CSS (simpler selectors)
MIT License
44 stars 9 forks source link

:matches is incorrectly implemented #16

Open jonathantneal opened 6 years ago

jonathantneal commented 6 years ago

Fairly significant news: https://github.com/w3c/csswg-drafts/issues/1027

UPDATED: May 31, 2018

The CSSWG has resolved 2 issues with :matches().

1. Matches uses the hierarchy of the entire document

The matches the behavior of :not, DOM matches, and querySelector.

Therefore, the following selector would match <body>:

head ~ :matches(html > body) {}

And it would effectively expand to:

html > head ~ body

It would not expand to:

head ~ html > body {} /* WRONG */

2. Matches uses the selector weight of the highest-weighted argument

This matches the behavior of :not and :nth-child(A of B). Therefore, the following selector would match <span class="foo bar"></span> with a weight of [1, 1, 0]:

.foo:matches(.bar, #qux) {}

The id weight would apply and the class weight would not, despite the match being the opposite. This could not be expanded in any yet-known polyfill, whether at build time or live.

You would otherwise somehow need to do this:

  1. Encounter :matches(.bar, #qux) and calculate its weight as [1, 0, 0].
  2. Match <span class="foo bar"></span> using .foo.bar.
  3. Change the element and the selector to match the calculated weight In HTML: <span class="foo bar" id="matches-bar"></span> And CSS: .foo#matches-bar
niksajanjic commented 6 years ago

https://drafts.csswg.org/selectors-4/#matches

Pseudo-elements cannot be represented by the matches-any pseudo-class; they are not valid within :matches().

If I'm understanding this correctly, pseudo-elements shouldn't be allowed inside :matches per specification.

I tested this code:

.test :matches(input, ::placeholder) { ... }

And it will produce this result:

.test input, .test ::placeholder { ... }

Not sure if the intention is to follow specification as closely as possible. If it is, I'm guessing we could check for appearance of :: in bodySelectors array of explodeSelector function and then throw a warning/error, maybe even just return [selector] silently? We could even check against an array of pseudo-elements (there aren't many of them) in case someone uses single : to express pseudo-element.

Any thoughts?

jonathantneal commented 5 years ago

I’m all for following the spec. I think this plugin needs to be deprecated. Otherwise, people will demand that this plugin support both the old pattern and the new pattern. It would be better if we let this plugin do what it has always done (and allow people to explicitly enable it in the next major release of PostCSS Preset Env), and then also create a new plugin for :is which follows the spec.