Skip to content

Commit 446e3df

Browse files
authored
css has pseudo : pseudo element support and .js-has-pseudo class (#525)
* css has pseudo : pseudo element support and .js-has-pseudo class * update tests
1 parent ff12c33 commit 446e3df

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+836
-489
lines changed

plugin-packs/postcss-preset-env/test/basic.autoprefixer.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@
269269
background-color: yellow;
270270
}
271271

272-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
272+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
273273
background-color: yellow;
274274
}
275275

plugin-packs/postcss-preset-env/test/basic.autoprefixer.false.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@
269269
background-color: yellow;
270270
}
271271

272-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
272+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
273273
background-color: yellow;
274274
}
275275

plugin-packs/postcss-preset-env/test/basic.ch38.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@
189189
background-color: yellow;
190190
}
191191

192-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
192+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
193193
background-color: yellow;
194194
}
195195

plugin-packs/postcss-preset-env/test/basic.ch88-ff78-saf10.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
188188
background-color: yellow;
189189
}
190190

191-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
191+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
192192
background-color: yellow;
193193
}
194194

plugin-packs/postcss-preset-env/test/basic.ch88-ff78.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
181181
background-color: yellow;
182182
}
183183

184-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
184+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
185185
background-color: yellow;
186186
}
187187

plugin-packs/postcss-preset-env/test/basic.ch88-ff78.no-is-pseudo.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
181181
background-color: yellow;
182182
}
183183

184-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
184+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
185185
background-color: yellow;
186186
}
187187

plugin-packs/postcss-preset-env/test/basic.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@
292292
background-color: yellow;
293293
}
294294

295-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
295+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
296296
background-color: yellow;
297297
}
298298

plugin-packs/postcss-preset-env/test/basic.ff49.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@
185185
background-color: yellow;
186186
}
187187

188-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
188+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
189189
background-color: yellow;
190190
}
191191

plugin-packs/postcss-preset-env/test/basic.ff66.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@
173173
background-color: yellow;
174174
}
175175

176-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
176+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
177177
background-color: yellow;
178178
}
179179

plugin-packs/postcss-preset-env/test/basic.ie10.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@
301301
background-color: yellow;
302302
}
303303

304-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
304+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
305305
background-color: yellow;
306306
}
307307

plugin-packs/postcss-preset-env/test/basic.nesting.false.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
290290
background-color: yellow;
291291
}
292292

293-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
293+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
294294
background-color: yellow;
295295
}
296296

plugin-packs/postcss-preset-env/test/basic.op_mini.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
276276
background-color: yellow;
277277
}
278278

279-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
279+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
280280
background-color: yellow;
281281
}
282282

plugin-packs/postcss-preset-env/test/basic.preserve.true.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
524524
background-color: yellow;
525525
}
526526

527-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
527+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
528528
background-color: yellow;
529529
}
530530

plugin-packs/postcss-preset-env/test/basic.safari15.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@
157157
background-color: yellow;
158158
}
159159

160-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
160+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
161161
background-color: yellow;
162162
}
163163

plugin-packs/postcss-preset-env/test/basic.stage0-ff49.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
190190
background-color: yellow;
191191
}
192192

193-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
193+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
194194
background-color: yellow;
195195
}
196196

plugin-packs/postcss-preset-env/test/basic.stage0-ff66.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
178178
background-color: yellow;
179179
}
180180

181-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
181+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
182182
background-color: yellow;
183183
}
184184

plugin-packs/postcss-preset-env/test/basic.stage0.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.te
297297
background-color: yellow;
298298
}
299299

300-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
300+
.js-has-pseudo [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
301301
background-color: yellow;
302302
}
303303

plugin-packs/postcss-preset-env/test/client-side-polyfills.stage-1.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
order: 3;
1111
}
1212

13-
[csstools-has-1m-2w-2p-37-14-1a-2p-15] {
13+
.js-has-pseudo [csstools-has-1m-2w-2p-37-14-1a-2p-15] {
1414
order: 4;
1515
}
1616

plugin-packs/postcss-preset-env/test/client-side-polyfills.stage-2.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
order: 3;
1111
}
1212

13-
[csstools-has-1m-2w-2p-37-14-1a-2p-15] {
13+
.js-has-pseudo [csstools-has-1m-2w-2p-37-14-1a-2p-15] {
1414
order: 4;
1515
}
1616

plugin-packs/postcss-preset-env/test/disable-client-side-polyfills.disabled.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ input:blank {
66
order: 1;
77
}
88

9-
[csstools-has-2p-1m-2w-2p-37-14-1q-w-2x-31-2v-15]:not(does-not-exist):not(does-not-exist) {
9+
.js-has-pseudo [csstools-has-2p-1m-2w-2p-37-14-1q-w-2x-31-2v-15]:not(does-not-exist):not(does-not-exist) {
1010
order: 2;
1111
}
1212

plugin-packs/postcss-preset-env/test/layers-basic.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ h1.test-custom-selectors:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):n
474474
background-color: yellow;
475475
}
476476

477-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) {
477+
.js-has-pseudo:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
478478
background-color: yellow;
479479
}
480480

plugin-packs/postcss-preset-env/test/layers-basic.preserve.true.expect.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,7 +535,7 @@ h1.test-custom-selectors:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):n
535535
background-color: yellow;
536536
}
537537

538-
[csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) {
538+
.js-has-pseudo:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) [csstools-has-1a-38-2t-37-38-19-2w-2p-37-19-34-37-2t-39-2s-33-19-2r-30-2p-37-37-1m-2w-2p-37-14-1a-2x-32-32-2t-36-19-2r-30-2p-37-37-15]:not(.does-not-exist) {
539539
background-color: yellow;
540540
}
541541

plugins/css-has-pseudo/.tape.mjs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ postcssTape(plugin)({
3838
},
3939
'browser': {
4040
message: 'prepare CSS for chrome test',
41-
options: {
42-
preserve: false
43-
}
4441
},
4542
'plugin-order-logical:before': {
4643
message: 'works with other plugins that modify selectors',

plugins/css-has-pseudo/src/browser.js

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,28 @@ import '@mrhenry/core-web/modules/~element-qsa-has.js';
44
import extractEncodedSelectors from './encode/extract.mjs';
55
import encodeCSS from './encode/encode.mjs';
66

7+
function hasNativeSupport(document) {
8+
try {
9+
// Chrome does not support forgiving selector lists in :has()
10+
document.querySelector(':has(*, :does-not-exist, > *)');
11+
document.querySelector(':has(:has(any))');
12+
13+
// Safari incorrectly returns the html element with this query
14+
if (document.querySelector(':has(:scope *)')) {
15+
return false;
16+
}
17+
18+
if (!('CSS' in self) || !('supports' in self.CSS) || !self.CSS.supports(':has(any)')) {
19+
return false;
20+
}
21+
22+
} catch (_) {
23+
return false;
24+
}
25+
26+
return true;
27+
}
28+
729
export default function cssHasPseudo(document, options) {
830
// OPTIONS
931
{
@@ -18,23 +40,7 @@ export default function cssHasPseudo(document, options) {
1840
forcePolyfill: (!!options.forcePolyfill) || false,
1941
};
2042

21-
if (!options.forcePolyfill) {
22-
try {
23-
// Chrome does not support forgiving selector lists in :has()
24-
document.querySelector(':has(*, :does-not-exist, > *)');
25-
26-
// Safari incorrectly returns the html element with this query
27-
if (!document.querySelector(':has(:scope *)')) {
28-
// Native support detected.
29-
// Doing early return.
30-
return;
31-
}
32-
33-
// fallthrough to polyfill
34-
} catch (_) {
35-
// fallthrough to polyfill
36-
}
37-
}
43+
options.mustPolyfill = options.forcePolyfill || !hasNativeSupport(document);
3844

3945
if (!Array.isArray(options.observedAttributes)) {
4046
options.observedAttributes = [];
@@ -56,6 +62,12 @@ export default function cssHasPseudo(document, options) {
5662

5763
// walk all stylesheets to collect observed css rules
5864
[].forEach.call(document.styleSheets, walkStyleSheet);
65+
if (!options.mustPolyfill) {
66+
// Cleanup of rules will have happened in `walkStyleSheet`
67+
// Native support will take over from here
68+
return;
69+
}
70+
5971
transformObservedItemsThrottled();
6072

6173
// observe DOM modifications that affect selectors
@@ -228,13 +240,20 @@ export default function cssHasPseudo(document, options) {
228240
// walk a css rule to collect observed css rules
229241
[].forEach.call(styleSheet.cssRules || [], (rule) => {
230242
if (rule.selectorText) {
243+
rule.selectorText = rule.selectorText.replace(/\.js-has-pseudo\s/g, '');
244+
231245
try {
232246
// decode the selector text in all browsers to:
233247
const hasSelectors = extractEncodedSelectors(rule.selectorText.toString());
234248
if (hasSelectors.length === 0) {
235249
return;
236250
}
237251

252+
if (!options.mustPolyfill) {
253+
rule.deleteRule();
254+
return;
255+
}
256+
238257
for (let i = 0; i < hasSelectors.length; i++) {
239258
const hasSelector = hasSelectors[i];
240259
observedItems.push({

0 commit comments

Comments
 (0)