postcss-selector-matches icon indicating copy to clipboard operation
postcss-selector-matches copied to clipboard

:matches is incorrectly implemented

Open jonathantneal opened this issue 7 years ago • 2 comments

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

jonathantneal avatar May 23 '18 04:05 jonathantneal

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?

niksajanjic avatar Sep 20 '18 09:09 niksajanjic

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.

jonathantneal avatar Feb 28 '19 12:02 jonathantneal