Skip to content

Commit a626c3d

Browse files
committed
Allow progressive enhancement using @supports
1 parent 8a1c1bd commit a626c3d

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

lib/DoIUse.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import multimatch from 'multimatch';
22

3+
import postcss from 'postcss';
34
import BrowserSelection from './BrowserSelection.js';
45
import Detector from './Detector.js';
56

@@ -101,6 +102,38 @@ export default class DoIUse {
101102
if (overwritees.length > 0) {
102103
return;
103104
}
105+
106+
// find the closest @supports parent
107+
/** @type {any} TODO Type this */
108+
let supports = usage.parent;
109+
while (supports && supports.type !== 'atrule' && supports.name !== 'supports') {
110+
supports = supports.parent;
111+
}
112+
if (supports) {
113+
// FIXME This is a very, VERY dirty hack
114+
// FIXME Handle e.g. `@supporst (content: ') and ('`)
115+
// TODO Report an warning if condition is too complex for us to understand
116+
// TODO Support `or`?
117+
// TODO Support nested brackets?
118+
const temporaryDeclarations = supports.params
119+
.split(/(?<=\))\s*and\s*(?=\()/g)
120+
.map((part) => part.trim().replaceAll(/^\(|\)$/g, ''))
121+
.filter((part) => !/^\s*not\s+/i.test(part));
122+
123+
const temporaryCss = `i { ${temporaryDeclarations.join(';\n')} }`;
124+
const temporaryCssTree = postcss.parse(temporaryCss);
125+
const supportsDetector = new Detector([feature]);
126+
const safeToUseFeatures = [];
127+
supportsDetector.process(
128+
temporaryCssTree,
129+
({ feature: supportsFeature }) => {
130+
safeToUseFeatures.push(supportsFeature);
131+
},
132+
);
133+
if (safeToUseFeatures.includes(feature)) {
134+
return;
135+
}
136+
}
104137
}
105138

106139
const messages = [];

test/postcss-progressive-enhancement.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,51 @@ test('Progressive enhancement using repeated CSS properties', (t) => {
2020

2121
t.end();
2222
});
23+
24+
test('Progressive enhancement using @supports', (t) => {
25+
const css = `
26+
p {
27+
display: block;
28+
}
29+
30+
@supports (display: grid) {
31+
p {
32+
display: grid;
33+
flex-wrap: wrap;
34+
}
35+
}
36+
`;
37+
38+
const result = postcss(new DoIUse({
39+
browsers: ['safari >= 9'],
40+
})).process(css);
41+
const warnings = result.warnings();
42+
43+
t.equal(warnings.length, 0, 'No warnings');
44+
45+
t.end();
46+
});
47+
48+
test('Progressive enhancement using @supports with multiple conditions', (t) => {
49+
const css = `
50+
p {
51+
display: block;
52+
}
53+
54+
@supports (display: flex) and (color: hsl(0, 0%, 0%)) {
55+
p {
56+
display: flex;
57+
background-color: hsl(0, 0%, 0%);
58+
}
59+
}
60+
`;
61+
62+
const result = postcss(new DoIUse({
63+
browsers: ['safari >= 9'],
64+
})).process(css);
65+
const warnings = result.warnings();
66+
67+
t.equal(warnings.length, 0, 'No warnings');
68+
69+
t.end();
70+
});

0 commit comments

Comments
 (0)