w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.5k stars 668 forks source link

[selectors-4] Exact attribute-substring matching #8124

Open jakob-e opened 1 year ago

jakob-e commented 1 year ago

The current attribute substring allows matching start and end of value

[attr^="value"]

// Will match 
1 <div attr="value">
2 <div attr="value list">
3 <div attr="values">
4 <div attr="value-list">

To add precision the substring start/end (^$) could be combined with the whitespace-separated flag (~) to ensure an exact match of the substring - simplifying the current :is([attr="value"],[attr^="value "]) solution

[attr^~="value"]

// Would only match
1 <div attr="value">
2 <div attr="value list">

Syntax suggestion

[attr^~="value"] { ... }
[attr$~="value"] { ... }

Spec: https://www.w3.org/TR/selectors-4/#attribute-representation https://www.w3.org/TR/selectors-4/#attribute-substrings

Loirooriol commented 1 year ago

What's your usecase? I think that space-separated values are typically unordered. And if they are ordered, just allowing to check for the 1st and last position may not be doing much.

jakob-e commented 1 year ago

I've changed the title to perhaps better illustrate my intend

A (IMO very stong) use case is targeting components and variations without collisions

[data-comp^~="card"] { ... }                     /* card component */ 
[data-comp^~="card"][data-comp~="news"] { ... }  /* news card variation */ 
[data-comp^~="card"][data-comp~="fancy"] { ... } /* fancy card variation */ 

// would match (in order)
<div data-comp="card">
<div data-comp="card news">
<div data-comp="card fancy">

The above syntax will allow creating

[data-comp^~="card-header"] { ... } /* card header component */
<div data-comp="card-header"> 

...without the latter also being matched by the card component selector (as it will - using the existing ^= syntax)

The reason I picked the whitespace ~ for my example syntax was to convey the same idea of bounding (exact match)

tabatkins commented 1 year ago

Yeah, it's not uncommon to have this ordered (or perhaps partially ordered, with the first token treated specially and the rest unordered) sort of token representation in design systems. The ^= misleads you a bit in this regard, leading to the exact mistake @jakob-e points out, where a [attr^="card"] ends up misfiring on "card-foo" subtypes.