├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── test.yml
├── .gitignore
├── .rollup.js
├── .tape.js
├── CHANGELOG.md
├── CONTRIBUTING.md
├── INSTALL.md
├── LICENSE.md
├── README.md
├── package.json
├── src
├── cli.js
├── lib
│ ├── get-transformed-insertions.js
│ ├── get-unsupported-browsers-by-feature.js
│ ├── ids-by-execution-order.js
│ ├── plugins-by-id.js
│ └── write-to-exports.js
├── patch
│ └── postcss-system-ui-font-family.js
└── postcss.js
└── test
├── basic.autoprefixer.expect.css
├── basic.autoprefixer.false.expect.css
├── basic.ch38.expect.css
├── basic.css
├── basic.expect.css
├── basic.ff49.expect.css
├── basic.nesting.expect.css
├── basic.stage0-ff49.expect.css
├── basic.stage0.expect.css
├── custom-properties.css
├── custom-properties.disabled.expect.css
├── custom-properties.enabled.expect.css
├── custom-properties.expect.css
├── generated-custom-exports.css
├── generated-custom-exports.js
├── generated-custom-exports.json
├── generated-custom-exports.mjs
├── import.css
├── import.expect.css
├── insert.after.expect.css
├── insert.before.expect.css
└── insert.css
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_style = tab
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
13 | [*.{json,md,yml}]
14 | indent_size = 2
15 | indent_style = space
16 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: test
2 | on:
3 | push:
4 |
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 | strategy:
9 | matrix:
10 | node: [12, 14, 16]
11 | steps:
12 | - uses: actions/checkout@v2
13 | - uses: actions/setup-node@v2
14 | with:
15 | node-version: ${{ matrix.node }}
16 | - run: npm install --ignore-scripts
17 | - run: npm run build
18 | - run: npm run test
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 | package-lock.json
4 | yarn.lock
5 | *.log*
6 | *.result.css
7 | .*
8 | !.editorconfig
9 | !.gitattributes
10 | !.github
11 | !.gitignore
12 | !.rollup.js
13 | !.tape.js
14 |
--------------------------------------------------------------------------------
/.rollup.js:
--------------------------------------------------------------------------------
1 | import pkg from './package.json'
2 |
3 | export default {
4 | ...pkg.rollup,
5 | plugins: pkg.rollup.plugins.map(plugin => require(plugin)()),
6 | onwarn(warning, warn) {
7 | if (warning.code !== 'UNRESOLVED_IMPORT') warn(warning)
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/.tape.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'basic': {
3 | message: 'supports basic usage'
4 | },
5 | 'basic:ff49': {
6 | message: 'supports { browsers: "ff >= 49" } usage',
7 | options: {
8 | browsers: 'ff >= 49'
9 | }
10 | },
11 | 'basic:ch38': {
12 | message: 'supports { browsers: "chrome >= 38" } usage',
13 | options: {
14 | browsers: 'chrome >= 38'
15 | }
16 | },
17 | 'basic:stage0': {
18 | message: 'supports { stage: 0 } usage',
19 | options: {
20 | stage: 0
21 | }
22 | },
23 | 'basic:stage0-ff49': {
24 | message: 'supports { browsers: "ff >= 49", stage: 0 } usage',
25 | options: {
26 | browsers: 'ff >= 49',
27 | stage: 0
28 | }
29 | },
30 | 'basic:nesting': {
31 | message: 'supports { stage: false, features: { "nesting-rules": true } } usage',
32 | options: {
33 | stage: false,
34 | features: {
35 | 'nesting-rules': true
36 | }
37 | }
38 | },
39 | 'basic:autoprefixer': {
40 | message: 'supports { autoprefixer: { add: false } } usage',
41 | options: {
42 | autoprefixer: {
43 | add: false
44 | }
45 | }
46 | },
47 | 'basic:autoprefixer:false': {
48 | message: 'supports { autoprefixer: false } usage',
49 | options: {
50 | autoprefixer: false
51 | }
52 | },
53 | 'custom-properties': {
54 | message: 'supports { browsers: "ie >= 10" } usage',
55 | options: {
56 | browsers: 'ie >= 10'
57 | }
58 | },
59 | 'custom-properties:disabled': {
60 | message: 'supports { browsers: "ie >= 10", features: { "custom-properties": false } } usage',
61 | options: {
62 | browsers: 'ie >= 10',
63 | features: {
64 | 'custom-properties': false
65 | }
66 | }
67 | },
68 | 'custom-properties:enabled': {
69 | message: 'supports { browsers: "chrome >= 60", features: { "custom-properties": true } } usage',
70 | options: {
71 | browsers: 'chrome >= 60',
72 | features: {
73 | 'custom-properties': true
74 | }
75 | }
76 | },
77 | 'insert:before': {
78 | message: 'supports { stage: 1, features: { "color-mod-function": true }, insertBefore: { "color-mod-function": [ require("postcss-simple-vars") ] } } usage',
79 | options: {
80 | stage: 1,
81 | features: {
82 | 'color-mod-function': true
83 | },
84 | insertBefore: {
85 | 'color-mod-function': [
86 | require('postcss-simple-vars')
87 | ]
88 | }
89 | }
90 | },
91 | 'insert:after': {
92 | message: 'supports { stage: 1, insertAfter: { "color-mod-function": [ require("postcss-simple-vars")() ] } } usage',
93 | options: {
94 | stage: 1,
95 | insertAfter: {
96 | 'color-mod-function': require('postcss-simple-vars')
97 | }
98 | },
99 | },
100 | 'insert:after:exec': {
101 | message: 'supports { stage: 2, features: { "color-mod-function": { unresolved: "ignore" } }, insertAfter: { "color-mod-function": require("postcss-simple-vars")() } } usage',
102 | options: {
103 | stage: 2,
104 | insertAfter: {
105 | 'color-mod-function': require('postcss-simple-vars')()
106 | }
107 | },
108 | expect: 'insert.after.expect.css'
109 | },
110 | 'insert:after:array': {
111 | message: 'supports { stage: 1, after: { "color-mod-function": [ require("postcss-simple-vars") ] } } usage',
112 | options: {
113 | stage: 1,
114 | insertAfter: {
115 | 'color-mod-function': [
116 | require('postcss-simple-vars')
117 | ]
118 | },
119 | features: {
120 | 'color-mod-function': {
121 | unresolved: 'ignore'
122 | }
123 | }
124 | },
125 | expect: 'insert.after.expect.css'
126 | },
127 | 'import': {
128 | message: 'supports { importFrom: { customMedia, customProperties, customSelectors, environmentVariables } } usage',
129 | options: {
130 | importFrom: {
131 | customMedia: {
132 | '--narrow-window': '(max-width: env(--sm))'
133 | },
134 | customProperties: {
135 | '--order': '1'
136 | },
137 | customSelectors: {
138 | ':--heading': 'h1, h2, h3, h4, h5, h6'
139 | },
140 | environmentVariables: {
141 | '--sm': '40rem'
142 | }
143 | },
144 | stage: 0
145 | }
146 | },
147 | 'basic:export': {
148 | message: 'supports { stage: 0 } usage',
149 | options: {
150 | stage: 0,
151 | exportTo: [
152 | 'test/generated-custom-exports.css',
153 | 'test/generated-custom-exports.js',
154 | 'test/generated-custom-exports.json',
155 | 'test/generated-custom-exports.mjs'
156 | ]
157 | },
158 | expect: 'basic.stage0.expect.css',
159 | result: 'basic.stage0.result.css',
160 | before() {
161 | global.__exportTo = {
162 | css: require('fs').readFileSync('test/generated-custom-exports.css', 'utf8'),
163 | js: require('fs').readFileSync('test/generated-custom-exports.js', 'utf8'),
164 | json: require('fs').readFileSync('test/generated-custom-exports.json', 'utf8'),
165 | mjs: require('fs').readFileSync('test/generated-custom-exports.mjs', 'utf8')
166 | };
167 | },
168 | after() {
169 | global.__exportAs = {
170 | css: require('fs').readFileSync('test/generated-custom-exports.css', 'utf8'),
171 | js: require('fs').readFileSync('test/generated-custom-exports.js', 'utf8'),
172 | json: require('fs').readFileSync('test/generated-custom-exports.json', 'utf8'),
173 | mjs: require('fs').readFileSync('test/generated-custom-exports.mjs', 'utf8')
174 | };
175 |
176 | Object.keys(global.__exportTo).forEach(key => {
177 | if (global.__exportTo[key] !== global.__exportAs[key]) {
178 | throw new Error(`The original ${key} file did not match the freshly exported copy`);
179 | }
180 | });
181 | }
182 | }
183 | };
184 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changes to PostCSS Preset Env
2 |
3 | ### 7.0.1 (November 19, 2021)
4 |
5 | - Fixed infinite loop in double-position-gradients [223](https://github.com/csstools/postcss-preset-env/issues/223)
6 | - Fixed "Unknown word" errors in when parsing CSS values [224](https://github.com/csstools/postcss-preset-env/issues/224)
7 | - Fixed "undefined" CSS values after transforms with postcss-place [225](https://github.com/csstools/postcss-preset-env/issues/225)
8 | - Updated `postcss-color-functional-notation` to 4.0.1 (patch)
9 | - Updated `postcss-double-position-gradients` to 3.0.1 (patch)
10 | - Updated `postcss-env-function` to 4.0.2 (patch)
11 | - Updated `postcss-image-set-function` to 4.0.2 (patch)
12 | - Updated `postcss-lab-function` to 4.0.1 (patch)
13 | - Updated `postcss-nesting` to 10.0.2 (patch)
14 | - Updated `postcss-place` to 7.0.1 (patch)
15 |
16 | ### 7.0.0 (November 16, 2021)
17 |
18 | - Updated `autoprefixer` to 10.4.0 (major)
19 | - Updated `browserslist` to 4.17.5 (minor)
20 | - Updated `caniuse-lite` to 1.0.30001272 (patch)
21 | - Updated `css-blank-pseudo` to 2.0.0 (major)
22 | - Updated `css-has-pseudo` to 2.0.0 (major)
23 | - Updated `css-prefers-color-scheme` to 5.0.0 (major)
24 | - Updated `cssdb` to 5.0.0 (major)
25 | - Updated `postcss` to 8.3.0 (major)
26 | - Updated `postcss-attribute-case-insensitive` to 5.0.0 (major)
27 | - Updated `postcss-color-functional-notation` to 4.0.0 (major)
28 | - Updated `postcss-color-hex-alpha` to 8.0.0 (major)
29 | - Updated `postcss-color-rebeccapurple` to 7.0.0 (major)
30 | - Updated `postcss-custom-media` to 8.0.0 (major)
31 | - Updated `postcss-custom-properties` to 12.0.0 (major)
32 | - Updated `postcss-custom-selectors` to 6.0.0 (major)
33 | - Updated `postcss-dir-pseudo-class` to 6.0.0 (major)
34 | - Updated `postcss-double-position-gradients` to 3.0.0 (major)
35 | - Updated `postcss-env-function` to 4.0.1 (major)
36 | - Updated `postcss-focus-visible` to 6.0.1 (major)
37 | - Updated `postcss-focus-within` to 5.0.1 (major)
38 | - Updated `postcss-font-variant` to 5.0.0 (major)
39 | - Updated `postcss-gap-properties` to 3.0.0 (major)
40 | - Updated `postcss-image-set-function` to 4.0.0 (major)
41 | - Updated `postcss-initial` to 3.0.4 (patch)
42 | - Updated `postcss-lab-function` to 4.0.0 (major)
43 | - Updated `postcss-logical` to 5.0.0 (major)
44 | - Updated `postcss-media-minmax` to 5.0.0 (major)
45 | - Updated `postcss-nesting` to 10.0.0 (major)
46 | - Updated `postcss-overflow-shorthand` to 3.0.0 (major)
47 | - Updated `postcss-page-break` to 3.0.4 (major)
48 | - Updated `postcss-place` to 7.0.0 (major)
49 | - Updated `postcss-pseudo-class-any-link` to 7.0.0 (major)
50 | - Updated `postcss-replace-overflow-wrap` to 4.0.0 (major)
51 | - Removed `postcss-selector-matches`
52 | - Removed `postcss-color-gray`
53 | - Updated support for Node 12+ (major)
54 |
55 | ### 6.7.0 (July 8, 2019)
56 |
57 | - Fixed the issue of autoprefixer alerting an upcoming change to the API
58 | - Updated `autoprefixer` to 9.6.1 (minor)
59 | - Updated `browserslist` to 4.6.4 (minor)
60 | - Updated `cssdb` to 4.4.0 (minor)
61 | - Updated `caniuse-lite` to 1.0.30000981 (patch)
62 | - Updated `postcss` to 7.0.17 (patch)
63 | - Updated `postcss-color-hex-alpha` to 5.0.3 (patch)
64 | - Updated `postcss-custom-media` to 7.0.8 (patch)
65 | - Updated `postcss-custom-properties` to 8.0.11 (patch)
66 |
67 | ### 6.6.0 (February 28, 2019)
68 |
69 | - Moved browserslist detection from using each input file per process to using
70 | the working directory on intialization, as was implied by the documentation.
71 | If fixing this previously undocumented behavior causes any harm to existing
72 | projects, it can be easily rolled back in a subsequent patch. For the
73 | majority of projects — those with a singular browserslist configuration and
74 | potentially many individually processed CSS files — we should expect reported
75 | build times around 35 seconds to drop to less than 2 seconds.
76 | - Updated `browserslist` to 4.4.2 (minor)
77 | - Updated `autoprefixer` to 9.4.9 (patch)
78 | - Updated `caniuse-lite` to 1.0.30000939 (patch)
79 | - Updated `postcss` to 7.0.14 (patch)
80 | - Updated `postcss-attribute-case-insensitive` to 4.0.1 (patch)
81 |
82 | ### 6.5.0 (December 12, 2018)
83 |
84 | - Added `css-blank-pseudo` polyfill
85 | - Added `css-has-pseudo` polyfill
86 | - Updated `autoprefixer` to 9.4.2 (minor)
87 | - Updated `browserslist` to 4.3.5 (minor)
88 | - Updated `caniuse-lite` to 1.0.30000918 (patch)
89 | - Updated `css-prefers-color-scheme` to 3.1.1 (minor, patch for this project)
90 | - Updated `cssdb` to 4.3.0 (minor)
91 | - Updated `postcss` to 7.0.6 (patch)
92 |
93 | ### 6.4.0 (November 6, 2018)
94 |
95 | - Fixed `exportTo` option to export Custom Media, Custom Properties, and Custom
96 | Selectors all to the same function, object, or file
97 | - Added `css-prefers-color-scheme` 3.0.0 (major, non-breaking for this project)
98 | - Updated `cssdb` to 4.2.0 (minor)
99 |
100 | ### 6.3.1 (November 5, 2018)
101 |
102 | - Updated `caniuse-lite` to 1.0.30000905 (patch)
103 | - Updated `postcss-custom-properties` to 8.0.9 (patch)
104 |
105 | ### 6.3.0 (October 28, 2018)
106 |
107 | - Added `postcss-double-position-gradients` 1.0.0 (major, non-breaking for this project)
108 | - Updated `autoprefixer` to 9.3.1 (minor)
109 | - Updated `browserslist` to 4.3.4 (patch)
110 | - Updated `caniuse-lite` to 1.0.30000899 (patch)
111 | - Updated `cssdb` to 4.1.0 (major, non-breaking for this project)
112 |
113 | ### 6.2.0 (October 22, 2018)
114 |
115 | - Updated `autoprefixer` to 9.2.1 (minor)
116 | - Updated `browserslist` to 4.3.1 (minor)
117 |
118 | ### 6.1.2 (October 19, 2018)
119 |
120 | - Updated `browserslist` to 4.2.1 (patch)
121 | - Updated `caniuse-lite` to 1.0.30000893 (patch)
122 | - Updated `postcss-custom-media` to 7.0.7 (patch)
123 |
124 | ### 6.1.1 (October 12, 2018)
125 |
126 | - Updated: `postcss-custom-media` to 7.0.6 (patch)
127 |
128 | ### 6.1.0 (October 10, 2018)
129 |
130 | - Added: `postcss-color-gray`
131 | - Added: Passing `autoprefixer: false` disables autoprefixer
132 | - Updated: `browserslist` to 4.2.0 (minor)
133 | - Updated: `caniuse-lite` to 1.0.30000890 (patch)
134 |
135 | ### 6.0.10 (October 2, 2018)
136 |
137 | - Updated: `postcss-custom-properties` to 8.0.8 (patch)
138 |
139 | ### 6.0.9 (October 2, 2018)
140 |
141 | - Updated: `browserslist` to 4.1.2 (patch)
142 | - Updated: `postcss` to 7.0.5 (patch)
143 | - Updated: `postcss-custom-properties` to 8.0.7 (patch)
144 |
145 | ### 6.0.8 (October 1, 2018)
146 |
147 | - Updated: `caniuse-lite` to 1.0.30000888 (patch)
148 | - Updated: `postcss` to 7.0.4 (patch)
149 |
150 | **Did you hear? PostCSS Preset Env is now part of Create React App!** 🎉
151 |
152 | ### 6.0.7 (September 23, 2018)
153 |
154 | - Updated: `postcss` to 7.0.3 (patch)
155 | - Updated: `postcss-custom-properties` to 8.0.6 (patch)
156 |
157 | ### 6.0.6 (September 23, 2018)
158 |
159 | - Updated: `postcss-custom-media` to 7.0.4 (patch)
160 |
161 | ### 6.0.5 (September 23, 2018)
162 |
163 | - Updated: `postcss-color-mod-function` to 3.0.3 (patch)
164 |
165 | ### 6.0.4 (September 23, 2018)
166 |
167 | - Updated: `caniuse-lite` to 1.0.30000887 (patch)
168 | - Updated: `postcss-color-mod-function` to 3.0.2 (patch)
169 |
170 | ### 6.0.3 (September 21, 2018)
171 |
172 | - Updated: `caniuse-lite` to 1.0.30000885 (patch)
173 | - Updated: `postcss-custom-properties` to 8.0.5 (patch)
174 |
175 | ### 6.0.2 (September 20, 2018)
176 |
177 | - Fixed: Do not break on an empty `importFrom` object
178 | - Fixed: Actually run `postcss-env-function`
179 |
180 | ### 6.0.1 (September 20, 2018)
181 |
182 | - Fixed: Issue with the `system-ui` font family polyfill by replacing
183 | `postcss-font-family-system-ui` with an internal polyfill, at least until the
184 | problem with the original plugin is resolved.
185 |
186 | ### 6.0.0 (September 20, 2018)
187 |
188 | - Added: Support for PostCSS 7+
189 | - Added: Support for PostCSS Values Parser 2+
190 | - Added: Support for PostCSS Selector Parser 5+
191 | - Added: Support for Node 6+
192 | - Updated: All 28 plugins
193 |
194 | ### 5.4.0 (July 25, 2018)
195 |
196 | - Added: `toggle` option to override which features are enabled or disabled
197 | - Deprecated: toggle features with `toggle`, not `features`
198 |
199 | ### 5.3.0 (July 24, 2018)
200 |
201 | - Updated: `postcss-lab-function` to v1.1.0 (minor update)
202 |
203 | ### 5.2.3 (July 21, 2018)
204 |
205 | - Updated: `postcss-color-mod-function` to v2.4.3 (patch update)
206 |
207 | ### 5.2.2 (July 13, 2018)
208 |
209 | - Updated: `autoprefixer` to v8.6.5 (patch update)
210 | - Updated: `caniuse-lite` to v1.0.30000865 (patch update)
211 | - Updated: `postcss-color-functional-notation` to v1.0.2 (patch update)
212 |
213 | ### 5.2.1 (June 26, 2018)
214 |
215 | - Updated: `caniuse-lite` to v1.0.30000859 (patch update)
216 | - Updated: `postcss-attribute-case-insensitive` to v3.0.1 (patch update)
217 |
218 | ### 5.2.0 (June 25, 2018)
219 |
220 | - Updated: `autoprefixer` to v8.6.3 (minor update)
221 | - Updated: `caniuse-lite` to v1.0.30000858 (patch update)
222 | - Updated: `postcss` to 6.0.23 (patch update)
223 | - Updated: `postcss-nesting` to v6.0.0 (major internal update, non-breaking for this project)
224 |
225 | ### 5.1.0 (May 21, 2018)
226 |
227 | - Added: `autoprefixer` option to pass options into autoprefixer
228 | - Updated: `autoprefixer` to v8.5.0 (minor update)
229 | - Updated: `browserslist` to v3.2.8 (patch update)
230 | - Updated: `caniuse-lite` to v1.0.30000844 (patch update)
231 | - Updated: `postcss-color-functional-notation` to v1.0.1 (patch update)
232 |
233 | ### 5.0.0 (May 11, 2018)
234 |
235 | - Added: `autoprefixer`
236 | - Added: `postcss-color-functional-notation`
237 | - Added: `postcss-env-function`
238 | - Added: `postcss-lab-function`
239 | - Added: `postcss-place`
240 | - Added: `postcss-gap-properties`
241 | - Added: `postcss-overflow-shorthand`
242 | - Updated: `cssdb` to v3.1.0 (major update)
243 | - Updated: In conformance with cssdb v3, the default stage is now 2
244 | - Updated: `postcss-attribute-case-insensitive` to v3.0.0 (major update)
245 | - Updated: `postcss-pseudo-class-any-link` to v5.0.0 (major update)
246 | - Updated: `postcss-image-set-function` to v2.0.0 (major update)
247 | - Updated: `postcss-dir-pseudo-class` to v4.0.0 (major update)
248 | - Updated: `postcss-color-rebeccapurple` to v3.1.0 (minor update)
249 | - Updated: `postcss` to v6.0.22 (patch update)
250 | - Updated: `browserslist` to v3.2.7 (patch update)
251 | - Updated: `caniuse-lite` to v1.0.30000839 (patch update)
252 |
253 | All plugins now conform to the latest stable releases of `postcss-value-parser`
254 | v1.5.0 and `postcss-selector-parser` v4.0.0.
255 |
256 | ### 4.1.0 (April 23, 2018)
257 |
258 | - Updated: `browserslist` to v3.2.5 (patch update)
259 | - Updated: `caniuse-lite` to v1.0.30000830 (patch update)
260 | - Updated: `postcss-apply` to v0.10.0 (minor update)
261 | - Updated: `postcss-nesting` to v5.0.0 (major update, non-breaking for this project)
262 |
263 | ### 4.0.0 (April 7, 2018)
264 |
265 | - Added: `postcss-focus-within`
266 | - Updated: `postcss-focus-visible` to v3.0.0 (major update)
267 | - Updated: `caniuse-lite` to v1.0.30000824 (patch update)
268 | - Updated: `cssdb` to v2.0.0 (major update)
269 | - Changed: All `specificationId` names to new `id` names for the `cssdb` update.
270 |
271 | ### 3.5.0 (April 5, 2018)
272 |
273 | - Fixed: `selectors-matches-pseudo` mapping to allow `:matches` polyfilling
274 | - Updated: `postcss-dir-pseudo-class` to v3.0.0 (major update, non-breaking for this project)
275 | - Updated: `postcss-logical` to v1.1.1 (minor update)
276 | - Updated: `postcss` to v6.0.21 (patch update)
277 | - Updated: `browserslist` to v3.2.4 (patch update)
278 | - Updated: `caniuse-lite` to v1.0.30000823 (patch update)
279 |
280 | ### 3.4.0 (March 18, 2018)
281 |
282 | - Updated: `browserslist` to v3.2.0 (minor update)
283 | - Updated: `postcss` to v6.0.20 (patch update)
284 | - Updated: `postcss-image-set-polyfill` to `@csstools/postcss-image-set-function` (hopefully temporarily)
285 |
286 | ### 3.3.0 (March 16, 2018)
287 |
288 | - Updated: `postcss-apply` to v0.9.0 (minor update)
289 | - Updated: `browserslist` to v3.1.2 (patch update)
290 | - Updated: `caniuse-lite` to v1.0.30000815 (patch update)
291 | - Updated: distribution to cjs and es bundles
292 |
293 | ### 3.2.2 (February 27, 2018)
294 |
295 | - Updated: `postcss-color-mod-function` to v2.4.2 (patch update)
296 |
297 | ### 3.2.1 (February 21, 2018)
298 |
299 | - Updated: Use the latest tested version of all dependencies
300 |
301 | ### 3.2.0 (February 18, 2018)
302 |
303 | - Added: `postcss-page-break` which has moved here from Autoprefixer
304 |
305 | ### 3.1.0 (February 17, 2018)
306 |
307 | - Added: `postcss-focus-visible`
308 |
309 | ### 3.0.0 (February 16, 2018)
310 |
311 | - Updated: `postcss-color-mod-function` to v2.4 (minor update)
312 | - Updated: `postcss-custom-properties` to v7.0 (major update)
313 |
314 | ### 2.2.0 (February 14, 2018)
315 |
316 | - Updated: `browserslist` to v3.1 (major update)
317 | - Updated: `postcss-color-mod-function` to v2.3 (minor update)
318 | - Improved: cleaned up one reusable variable and added a few tests
319 |
320 | ### 2.1.0 (January 22, 2018)
321 |
322 | - Updated: `cssdb` to v1.5 (minor update)
323 | - Updated: `postcss-color-mod-function` to v2.2 (major update)
324 | - Updated: `postcss-font-family-system-ui` to v3.0 (repo update)
325 |
326 | ### 2.0.0 (January 16, 2018)
327 |
328 | - Initial version
329 |
330 | ### 1.0.0 (December 20, 2017)
331 |
332 | - Unsupported version accidentally published by a member of the community
333 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to PostCSS Preset Env
2 |
3 | You want to help? You rock! Now, take a moment to be sure your contributions
4 | make sense to everyone else.
5 |
6 | ## Reporting Issues
7 |
8 | Found a problem? Want a new feature?
9 |
10 | - See if your issue or idea has [already been reported].
11 | - Provide a [reduced test case] or a [live example].
12 |
13 | Remember, a bug is a _demonstrable problem_ caused by _our_ code.
14 |
15 | ## Submitting Pull Requests
16 |
17 | Pull requests are the greatest contributions, so be sure they are focused in
18 | scope and avoid unrelated commits.
19 |
20 | 1. To begin; [fork this project], clone your fork, and add our upstream.
21 | ```bash
22 | # Clone your fork of the repo into the current directory
23 | git clone git@github.com:YOUR_USER/postcss-preset-env.git
24 |
25 | # Navigate to the newly cloned directory
26 | cd postcss-preset-env
27 |
28 | # Assign the original repo to a remote called "upstream"
29 | git remote add upstream git@github.com:csstools/postcss-preset-env.git
30 |
31 | # Install the tools necessary for testing
32 | npm install
33 | ```
34 |
35 | 2. Create a branch for your feature or fix:
36 | ```bash
37 | # Move into a new branch for your feature
38 | git checkout -b feature/thing
39 | ```
40 | ```bash
41 | # Move into a new branch for your fix
42 | git checkout -b fix/something
43 | ```
44 |
45 | 3. If your code follows our practices, then push your feature branch:
46 | ```bash
47 | # Test current code
48 | npm test
49 | ```
50 | ```bash
51 | # Push the branch for your new feature
52 | git push origin feature/thing
53 | ```
54 | ```bash
55 | # Or, push the branch for your update
56 | git push origin update/something
57 | ```
58 |
59 | That’s it! Now [open a pull request] with a clear title and description.
60 |
61 | ## Adding a new plugin to Postcss Preset Env
62 |
63 | If you want to add a new plugin, follow the
64 | [pull request guidelines](#submitting-pull-requests) while making these changes:
65 |
66 | - Ensure the feature exists in [cssdb](https://cssdb.org/).
67 | - Add the plugin to the `dependencies` list in [`package.json`](package.json).
68 | - Add the plugin to
69 | [`lib/plugins-by-id.js`](lib/plugins-by-id.js).
70 |
71 | [already been reported]: issues
72 | [fork this project]: fork
73 | [live example]: https://codepen.io/pen
74 | [open a pull request]: https://help.github.com/articles/using-pull-requests/
75 | [reduced test case]: https://css-tricks.com/reduced-test-cases/
76 |
--------------------------------------------------------------------------------
/INSTALL.md:
--------------------------------------------------------------------------------
1 | # Installing PostCSS Preset Env
2 |
3 | [PostCSS Preset Env] runs in all Node environments, with special instructions for:
4 |
5 | | [Node](#node) | [PostCSS CLI](#postcss-cli) | [Webpack](#webpack) | [Create React App](#create-react-app) | [Gulp](#gulp) | [Grunt](#grunt) | [Rollup](#rollup) |
6 | | --- | --- | --- | --- | --- | --- | --- |
7 |
8 | ## Node
9 |
10 | Add [PostCSS Preset Env] to your project:
11 |
12 | ```bash
13 | npm install postcss-preset-env --save-dev
14 | ```
15 |
16 | Use [PostCSS Preset Env] to process your CSS:
17 |
18 | ```js
19 | const postcssPresetEnv = require('postcss-preset-env');
20 |
21 | postcssPresetEnv.process(YOUR_CSS /*, processOptions, pluginOptions */);
22 | ```
23 |
24 | Or use it as a [PostCSS] plugin:
25 |
26 | ```js
27 | const postcss = require('postcss');
28 | const postcssPresetEnv = require('postcss-preset-env');
29 |
30 | postcss([
31 | postcssPresetEnv(/* pluginOptions */)
32 | ]).process(YOUR_CSS /*, processOptions */);
33 | ```
34 |
35 | ## PostCSS CLI
36 |
37 | Add [PostCSS CLI] to your project:
38 |
39 | ```bash
40 | npm install postcss-cli --save-dev
41 | ```
42 |
43 | Use [PostCSS Preset Env] in your `postcss.config.js` configuration file:
44 |
45 | ```js
46 | const postcssPresetEnv = require('postcss-preset-env');
47 |
48 | module.exports = {
49 | plugins: [
50 | postcssPresetEnv(/* pluginOptions */)
51 | ]
52 | }
53 | ```
54 |
55 | ## Webpack
56 |
57 | Add [PostCSS Loader] to your project:
58 |
59 | ```bash
60 | npm install postcss-loader --save-dev
61 | ```
62 |
63 | Use [PostCSS Preset Env] in your Webpack configuration:
64 |
65 | ```js
66 | const postcssPresetEnv = require('postcss-preset-env');
67 |
68 | module.exports = {
69 | module: {
70 | rules: [
71 | {
72 | test: /\.css$/,
73 | use: [
74 | 'style-loader',
75 | { loader: 'css-loader', options: { importLoaders: 1 } },
76 | {
77 | loader: 'postcss-loader',
78 | options: {
79 | postcssOptions: {
80 | plugins: [postcssPresetEnv(/* pluginOptions */)],
81 | },
82 | },
83 | },
84 | ],
85 | },
86 | ],
87 | },
88 | };
89 | ```
90 |
91 | ## Create React App
92 |
93 | **PostCSS Preset Env is already bundled with Create React App 2.**
94 |
95 | For Create React App 1, add [React App Rewired] and [React App Rewire PostCSS]
96 | to your project:
97 |
98 | ```bash
99 | npm install react-app-rewired react-app-rewire-postcss --save-dev
100 | ```
101 |
102 | Use [React App Rewire PostCSS] and [PostCSS Preset Env] in your
103 | `config-overrides.js` file:
104 |
105 | ```js
106 | const reactAppRewirePostcss = require('react-app-rewire-postcss');
107 | const postcssPresetEnv = require('postcss-preset-env');
108 |
109 | module.exports = config => reactAppRewirePostcss(config, {
110 | plugins: () => [
111 | postcssPresetEnv(/* pluginOptions */)
112 | ]
113 | });
114 | ```
115 |
116 | ## Gulp
117 |
118 | Add [Gulp PostCSS] to your project:
119 |
120 | ```bash
121 | npm install gulp-postcss --save-dev
122 | ```
123 |
124 | Use [PostCSS Preset Env] in your Gulpfile:
125 |
126 | ```js
127 | const postcss = require('gulp-postcss');
128 | const postcssPresetEnv = require('postcss-preset-env');
129 |
130 | gulp.task('css', () => gulp.src('./src/*.css').pipe(
131 | postcss([
132 | postcssPresetEnv(/* pluginOptions */)
133 | ])
134 | ).pipe(
135 | gulp.dest('.')
136 | ));
137 | ```
138 |
139 | ## Grunt
140 |
141 | Add [Grunt PostCSS] to your project:
142 |
143 | ```bash
144 | npm install grunt-postcss --save-dev
145 | ```
146 |
147 | Use [PostCSS Preset Env] in your Gruntfile:
148 |
149 | ```js
150 | const postcssPresetEnv = require('postcss-preset-env');
151 |
152 | grunt.loadNpmTasks('grunt-postcss');
153 |
154 | grunt.initConfig({
155 | postcss: {
156 | options: {
157 | processors: [
158 | postcssPresetEnv(/* pluginOptions */)
159 | ]
160 | },
161 | dist: {
162 | src: '*.css'
163 | }
164 | }
165 | });
166 | ```
167 |
168 | ## Rollup
169 |
170 | Complete [PostCSS CLI](#postcss-cli) setup.
171 |
172 | Add [Rollup Plugin PostCSS] to your project:
173 |
174 | ```bash
175 | npm install rollup-plugin-postcss --save-dev
176 | ```
177 |
178 | Use [Rollup Plugin PostCSS] in your rollup.config.js:
179 |
180 | ```js
181 | import postcss from 'rollup-plugin-postcss';
182 |
183 | module.exports = {
184 | input: '...',
185 | output: {...},
186 | plugins: [
187 | postcss({/* options */ })
188 | ]
189 | };
190 | ```
191 |
192 | [Gulp PostCSS]: https://github.com/postcss/gulp-postcss
193 | [Grunt PostCSS]: https://github.com/nDmitry/grunt-postcss
194 | [PostCSS]: https://github.com/postcss/postcss
195 | [PostCSS CLI]: https://github.com/postcss/postcss-cli
196 | [PostCSS Loader]: https://github.com/postcss/postcss-loader
197 | [PostCSS Preset Env]: https://github.com/csstools/postcss-preset-env
198 | [React App Rewire PostCSS]: https://github.com/csstools/react-app-rewire-postcss
199 | [React App Rewired]: https://github.com/timarney/react-app-rewired
200 | [Rollup Plugin PostCSS]: https://github.com/egoist/rollup-plugin-postcss
201 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # CC0 1.0 Universal
2 |
3 | ## Statement of Purpose
4 |
5 | The laws of most jurisdictions throughout the world automatically confer
6 | exclusive Copyright and Related Rights (defined below) upon the creator and
7 | subsequent owner(s) (each and all, an “owner”) of an original work of
8 | authorship and/or a database (each, a “Work”).
9 |
10 | Certain owners wish to permanently relinquish those rights to a Work for the
11 | purpose of contributing to a commons of creative, cultural and scientific works
12 | (“Commons”) that the public can reliably and without fear of later claims of
13 | infringement build upon, modify, incorporate in other works, reuse and
14 | redistribute as freely as possible in any form whatsoever and for any purposes,
15 | including without limitation commercial purposes. These owners may contribute
16 | to the Commons to promote the ideal of a free culture and the further
17 | production of creative, cultural and scientific works, or to gain reputation or
18 | greater distribution for their Work in part through the use and efforts of
19 | others.
20 |
21 | For these and/or other purposes and motivations, and without any expectation of
22 | additional consideration or compensation, the person associating CC0 with a
23 | Work (the “Affirmer”), to the extent that he or she is an owner of Copyright
24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and
25 | publicly distribute the Work under its terms, with knowledge of his or her
26 | Copyright and Related Rights in the Work and the meaning and intended legal
27 | effect of CC0 on those rights.
28 |
29 | 1. Copyright and Related Rights. A Work made available under CC0 may be
30 | protected by copyright and related or neighboring rights (“Copyright and
31 | Related Rights”). Copyright and Related Rights include, but are not limited
32 | to, the following:
33 | 1. the right to reproduce, adapt, distribute, perform, display, communicate,
34 | and translate a Work;
35 | 2. moral rights retained by the original author(s) and/or performer(s);
36 | 3. publicity and privacy rights pertaining to a person’s image or likeness
37 | depicted in a Work;
38 | 4. rights protecting against unfair competition in regards to a Work,
39 | subject to the limitations in paragraph 4(i), below;
40 | 5. rights protecting the extraction, dissemination, use and reuse of data in
41 | a Work;
42 | 6. database rights (such as those arising under Directive 96/9/EC of the
43 | European Parliament and of the Council of 11 March 1996 on the legal
44 | protection of databases, and under any national implementation thereof,
45 | including any amended or successor version of such directive); and
46 | 7. other similar, equivalent or corresponding rights throughout the world
47 | based on applicable law or treaty, and any national implementations
48 | thereof.
49 |
50 | 2. Waiver. To the greatest extent permitted by, but not in contravention of,
51 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
52 | unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright
53 | and Related Rights and associated claims and causes of action, whether now
54 | known or unknown (including existing as well as future claims and causes of
55 | action), in the Work (i) in all territories worldwide, (ii) for the maximum
56 | duration provided by applicable law or treaty (including future time
57 | extensions), (iii) in any current or future medium and for any number of
58 | copies, and (iv) for any purpose whatsoever, including without limitation
59 | commercial, advertising or promotional purposes (the “Waiver”). Affirmer
60 | makes the Waiver for the benefit of each member of the public at large and
61 | to the detriment of Affirmer’s heirs and successors, fully intending that
62 | such Waiver shall not be subject to revocation, rescission, cancellation,
63 | termination, or any other legal or equitable action to disrupt the quiet
64 | enjoyment of the Work by the public as contemplated by Affirmer’s express
65 | Statement of Purpose.
66 |
67 | 3. Public License Fallback. Should any part of the Waiver for any reason be
68 | judged legally invalid or ineffective under applicable law, then the Waiver
69 | shall be preserved to the maximum extent permitted taking into account
70 | Affirmer’s express Statement of Purpose. In addition, to the extent the
71 | Waiver is so judged Affirmer hereby grants to each affected person a
72 | royalty-free, non transferable, non sublicensable, non exclusive,
73 | irrevocable and unconditional license to exercise Affirmer’s Copyright and
74 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
75 | maximum duration provided by applicable law or treaty (including future time
76 | extensions), (iii) in any current or future medium and for any number of
77 | copies, and (iv) for any purpose whatsoever, including without limitation
78 | commercial, advertising or promotional purposes (the “License”). The License
79 | shall be deemed effective as of the date CC0 was applied by Affirmer to the
80 | Work. Should any part of the License for any reason be judged legally
81 | invalid or ineffective under applicable law, such partial invalidity or
82 | ineffectiveness shall not invalidate the remainder of the License, and in
83 | such case Affirmer hereby affirms that he or she will not (i) exercise any
84 | of his or her remaining Copyright and Related Rights in the Work or (ii)
85 | assert any associated claims and causes of action with respect to the Work,
86 | in either case contrary to Affirmer’s express Statement of Purpose.
87 |
88 | 4. Limitations and Disclaimers.
89 | 1. No trademark or patent rights held by Affirmer are waived, abandoned,
90 | surrendered, licensed or otherwise affected by this document.
91 | 2. Affirmer offers the Work as-is and makes no representations or warranties
92 | of any kind concerning the Work, express, implied, statutory or
93 | otherwise, including without limitation warranties of title,
94 | merchantability, fitness for a particular purpose, non infringement, or
95 | the absence of latent or other defects, accuracy, or the present or
96 | absence of errors, whether or not discoverable, all to the greatest
97 | extent permissible under applicable law.
98 | 3. Affirmer disclaims responsibility for clearing rights of other persons
99 | that may apply to the Work or any use thereof, including without
100 | limitation any person’s Copyright and Related Rights in the Work.
101 | Further, Affirmer disclaims responsibility for obtaining any necessary
102 | consents, permissions or other rights required for any use of the Work.
103 | 4. Affirmer understands and acknowledges that Creative Commons is not a
104 | party to this document and has no duty or obligation with respect to this
105 | CC0 or use of the Work.
106 |
107 | For more information, please see
108 | http://creativecommons.org/publicdomain/zero/1.0/.
109 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
3 |
4 | # PostCSS Preset Env [
][postcss]
5 |
6 | [
][npm-url]
7 | [
][cli-url]
8 | [
][git-url]
9 |
10 | [PostCSS Preset Env] lets you convert modern CSS into something most browsers
11 | can understand, determining the polyfills you need based on your targeted
12 | browsers or runtime environments.
13 |
14 | ```bash
15 | npm install postcss-preset-env
16 | ```
17 |
18 | ```pcss
19 | @custom-media --viewport-medium (width <= 50rem);
20 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
21 |
22 | :root {
23 | --mainColor: #12345678;
24 | }
25 |
26 | body {
27 | color: var(--mainColor);
28 | font-family: system-ui;
29 | overflow-wrap: break-word;
30 | }
31 |
32 | :--heading {
33 | background-image: image-set(url(img/heading.png) 1x, url(img/heading@2x.png) 2x);
34 |
35 | @media (--viewport-medium) {
36 | margin-block: 0;
37 | }
38 | }
39 |
40 | a {
41 | color: rgb(0 0 100% / 90%);
42 |
43 | &:hover {
44 | color: rebeccapurple;
45 | }
46 | }
47 |
48 | /* becomes */
49 |
50 | :root {
51 | --mainColor: rgba(18, 52, 86, 0.47059);
52 | }
53 |
54 | body {
55 | color: rgba(18, 52, 86, 0.47059);
56 | color: var(--mainColor);
57 | font-family: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Droid Sans, Helvetica Neue;
58 | word-wrap: break-word;
59 | }
60 |
61 | h1, h2, h3, h4, h5, h6 {
62 | background-image: url(img/heading.png);
63 | }
64 |
65 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
66 | h1, h2, h3, h4, h5, h6 {
67 | background-image: url(img/heading@2x.png)
68 | }
69 | }
70 |
71 | @media (max-width: 50rem) {
72 | h1, h2, h3, h4, h5, h6 {
73 | margin-top: 0;
74 | margin-bottom: 0;
75 | }
76 | }
77 |
78 | a {
79 | color: rgba(0, 0, 255, 0.9)
80 | }
81 |
82 | a:hover {
83 | color: #639;
84 | }
85 | ```
86 |
87 | Without any configuration options, [PostCSS Preset Env] enables **Stage 2**
88 | features and supports **all** browsers.
89 |
90 | [![Transform with Preset Env][readme-transform-with-preset-env-img]][readme-transform-with-preset-env-url]
91 | [![Style with Preset Env][readme-style-with-preset-env-img]][readme-style-with-preset-env-url]
92 |
93 | ## Usage
94 |
95 | Add [PostCSS Preset Env] to your project:
96 |
97 | ```bash
98 | npm install postcss-preset-env --save-dev
99 | ```
100 |
101 | Use [PostCSS Preset Env] to process your CSS:
102 |
103 | ```js
104 | const postcssPresetEnv = require('postcss-preset-env');
105 |
106 | postcssPresetEnv.process(YOUR_CSS /*, processOptions, pluginOptions */);
107 | ```
108 |
109 | Or use it as a [PostCSS] plugin:
110 |
111 | ```js
112 | const postcss = require('postcss');
113 | const postcssPresetEnv = require('postcss-preset-env');
114 |
115 | postcss([
116 | postcssPresetEnv(/* pluginOptions */)
117 | ]).process(YOUR_CSS /*, processOptions */);
118 | ```
119 |
120 | [PostCSS Preset Env] runs in all Node environments, with special instructions for:
121 |
122 | | [Node](INSTALL.md#node) | [PostCSS CLI](INSTALL.md#postcss-cli) | [Webpack](INSTALL.md#webpack) | [Create React App](INSTALL.md#create-react-app) | [Gulp](INSTALL.md#gulp) | [Grunt](INSTALL.md#grunt) | [Rollup](INSTALL.md#rollup) |
123 | | --- | --- | --- | --- | --- | --- | --- |
124 |
125 | ## Options
126 |
127 | ### stage
128 |
129 | The `stage` option determines which CSS features to polyfill, based upon their
130 | stability in the process of becoming implemented web standards.
131 |
132 | ```js
133 | postcssPresetEnv({ stage: 0 })
134 | ```
135 |
136 | The `stage` can be `0` (experimental) through `4` (stable), or `false`. Setting
137 | `stage` to `false` will disable every polyfill. Doing this would only be useful
138 | if you intended to exclusively use the [`features`](#features) option.
139 |
140 | Without any configuration options, [PostCSS Preset Env] enables **Stage 2**
141 | features.
142 |
143 | ### features
144 |
145 | The `features` option enables or disables specific polyfills by ID. Passing
146 | `true` to a specific feature ID will enable its polyfill, while passing `false`
147 | will disable it. [List of IDs](https://github.com/csstools/postcss-preset-env/blob/master/src/lib/plugins-by-id.js#L36)
148 |
149 | ```js
150 | postcssPresetEnv({
151 | /* use stage 3 features + css nesting rules */
152 | stage: 3,
153 | features: {
154 | 'nesting-rules': true
155 | }
156 | })
157 | ```
158 |
159 | Passing an object to a specific feature ID will both enable and configure it.
160 |
161 | ```js
162 | postcssPresetEnv({
163 | /* use stage 3 features + css color-mod (warning on unresolved) */
164 | stage: 3,
165 | features: {
166 | 'color-mod-function': { unresolved: 'warn' }
167 | }
168 | })
169 | ```
170 |
171 | Any polyfills not explicitly enabled or disabled through `features` are
172 | determined by the [`stage`](#stage) option.
173 |
174 | ### browsers
175 |
176 | The `browsers` option determines which polyfills are required based upon the
177 | browsers you are supporting.
178 |
179 | [PostCSS Preset Env] supports any standard [browserslist] configuration, which
180 | can be a `.browserslistrc` file, a `browserslist` key in `package.json`, or
181 | `browserslist` environment variables.
182 |
183 | The `browsers` option should only be used when a standard browserslist
184 | configuration is not available.
185 |
186 | ```js
187 | postcssPresetEnv({ browsers: 'last 2 versions' })
188 | ```
189 |
190 | If not valid browserslist configuration is specified, the
191 | [default browserslist query](https://github.com/browserslist/browserslist#queries)
192 | will be used.
193 |
194 | ### insertBefore / insertAfter
195 |
196 | The `insertBefore` and `insertAfter` keys allow you to insert other PostCSS
197 | plugins into the chain. This is only useful if you are also using sugary
198 | PostCSS plugins that must execute before or after certain polyfills.
199 | Both `insertBefore` and `insertAfter` support chaining one or multiple plugins.
200 |
201 | ```js
202 | import postcssSimpleVars from 'postcss-simple-vars';
203 |
204 | postcssPresetEnv({
205 | insertBefore: {
206 | 'all-property': postcssSimpleVars
207 | }
208 | })
209 | ```
210 |
211 | ### autoprefixer
212 |
213 | [PostCSS Preset Env] includes [autoprefixer] and [`browsers`](#browsers) option
214 | will be passed to it automatically.
215 |
216 | Specifying the `autoprefixer` option enables passing
217 | [additional options](https://github.com/postcss/autoprefixer#options)
218 | into [autoprefixer].
219 |
220 | ```js
221 | postcssPresetEnv({
222 | autoprefixer: { grid: true }
223 | })
224 | ```
225 |
226 | Passing `autoprefixer: false` disables autoprefixer.
227 |
228 | ### preserve
229 |
230 | The `preserve` option determines whether all plugins should receive a
231 | `preserve` option, which may preserve or remove otherwise-polyfilled CSS. By
232 | default, this option is not configured.
233 |
234 | ```js
235 | postcssPresetEnv({
236 | preserve: false // instruct all plugins to omit pre-polyfilled CSS
237 | });
238 | ```
239 |
240 | ### importFrom
241 |
242 | The `importFrom` option specifies sources where variables like Custom Media,
243 | Custom Properties, Custom Selectors, and Environment Variables can be imported
244 | from, which might be CSS, JS, and JSON files, functions, and directly passed
245 | objects.
246 |
247 | ```js
248 | postcssPresetEnv({
249 | /*
250 | @custom-media --small-viewport (max-width: 30em);
251 | @custom-selector :--heading h1, h2, h3;
252 | :root { --color: red; }
253 | */
254 | importFrom: 'path/to/file.css'
255 | });
256 | ```
257 |
258 | Multiple sources can be passed into this option, and they will be parsed in the
259 | order they are received. JavaScript files, JSON files, functions, and objects
260 | will use different namespaces to import different kinds of variables.
261 |
262 | ```js
263 | postcssPresetEnv({
264 | importFrom: [
265 | /*
266 | @custom-media --small-viewport (max-width: 30em);
267 | @custom-selector :--heading h1, h2, h3;
268 | :root { --color: red; }
269 | */
270 | 'path/to/file.css',
271 |
272 | /* module.exports = {
273 | customMedia: { '--small-viewport': '(max-width: 30em)' },
274 | customProperties: { '--color': 'red' },
275 | customSelectors: { ':--heading': 'h1, h2, h3' },
276 | environmentVariables: { '--branding-padding': '20px' }
277 | } */
278 | 'and/then/this.js',
279 |
280 | /* {
281 | "custom-media": { "--small-viewport": "(max-width: 30em)" }
282 | "custom-properties": { "--color": "red" },
283 | "custom-selectors": { ":--heading": "h1, h2, h3" },
284 | "environment-variables": { "--branding-padding": "20px" }
285 | } */
286 | 'and/then/that.json',
287 |
288 | {
289 | customMedia: { '--small-viewport': '(max-width: 30em)' },
290 | customProperties: { '--color': 'red' },
291 | customSelectors: { ':--heading': 'h1, h2, h3' },
292 | environmentVariables: { '--branding-padding': '20px' }
293 | },
294 | () => {
295 | const customMedia = { '--small-viewport': '(max-width: 30em)' };
296 | const customProperties = { '--color': 'red' };
297 | const customSelectors = { ':--heading': 'h1, h2, h3' };
298 | const environmentVariables = { '--branding-padding': '20px' };
299 |
300 | return { customMedia, customProperties, customSelectors, environmentVariables };
301 | }
302 | ]
303 | });
304 | ```
305 |
306 | ### exportTo
307 |
308 | The `exportTo` option specifies destinations where variables like Custom Media,
309 | Custom Properties, Custom Selectors, and Environment Variables can be exported
310 | to, which might be CSS, JS, and JSON files, functions, and directly passed
311 | objects.
312 |
313 | ```js
314 | postcssPresetEnv({
315 | /*
316 | @custom-media --small-viewport (max-width: 30em);
317 | @custom-selector :--heading h1, h2, h3;
318 | :root { --color: red; }
319 | */
320 | exportTo: 'path/to/file.css'
321 | });
322 | ```
323 |
324 | Multiple destinations can be passed into this option as well, and they will be
325 | parsed in the order they are received. JavaScript files, JSON files, and
326 | objects will use different namespaces to import different kinds of variables.
327 |
328 | ```js
329 | const cachedObject = {};
330 |
331 | postcssPresetEnv({
332 | exportTo: [
333 | /*
334 | @custom-media --small-viewport (max-width: 30em);
335 | @custom-selector :--heading h1, h2, h3;
336 | :root { --color: red; }
337 | */
338 | 'path/to/file.css',
339 |
340 | /* module.exports = {
341 | customMedia: { '--small-viewport': '(max-width: 30em)' },
342 | customProperties: { '--color': 'red' },
343 | customSelectors: { ':--heading': 'h1, h2, h3' },
344 | environmentVariables: { '--branding-padding': '20px' }
345 | } */
346 | 'and/then/this.js',
347 |
348 | /* {
349 | "custom-media": { "--small-viewport": "(max-width: 30em)" }
350 | "custom-properties": { "--color": "red" },
351 | "custom-selectors": { ":--heading": "h1, h2, h3" },
352 | "environment-variables": { "--branding-padding": "20px" }
353 | } */
354 | 'and/then/that.json',
355 |
356 | cachedObject,
357 | variables => {
358 | if ('customProperties' in variables) {
359 | // do something special with customProperties
360 | }
361 |
362 | Object.assign(cachedObject, variables);
363 | }
364 | ]
365 | });
366 | ```
367 |
368 | [cli-img]: https://github.com/postcss/postcss-preset-env/workflows/test/badge.svg
369 | [cli-url]: https://github.com/postcss/postcss-preset-env/actions/workflows/test.yml?query=workflow/test
370 | [git-img]: https://img.shields.io/badge/support-chat-blue.svg
371 | [git-url]: https://gitter.im/postcss/postcss
372 | [npm-img]: https://img.shields.io/npm/v/postcss-preset-env.svg
373 | [npm-url]: https://www.npmjs.com/package/postcss-preset-env
374 |
375 | [autoprefixer]: https://github.com/postcss/autoprefixer
376 | [browserslist]: https://github.com/browserslist/browserslist#readme
377 | [caniuse]: https://caniuse.com/
378 | [cssdb]: https://cssdb.org/
379 | [PostCSS]: https://github.com/postcss/postcss
380 | [PostCSS Preset Env]: https://github.com/csstools/postcss-preset-env
381 | [readme-style-with-preset-env-img]: https://csstools.github.io/postcss-preset-env/readme-style-with-preset-env.svg
382 | [readme-style-with-preset-env-url]: https://codepen.io/pen?template=OZRovK
383 | [readme-transform-with-preset-env-img]: https://csstools.github.io/postcss-preset-env/readme-transform-with-preset-env.svg
384 | [readme-transform-with-preset-env-url]: https://csstools.github.io/postcss-preset-env/
385 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postcss-preset-env",
3 | "version": "7.0.1",
4 | "description": "Convert modern CSS into something browsers understand",
5 | "author": "Jonathan Neal ",
6 | "license": "CC0-1.0",
7 | "repository": "csstools/postcss-preset-env",
8 | "homepage": "https://github.com/csstools/postcss-preset-env#readme",
9 | "bugs": "https://github.com/csstools/postcss-preset-env/issues",
10 | "main": "dist/index.js",
11 | "module": "dist/index.mjs",
12 | "files": [
13 | "dist"
14 | ],
15 | "scripts": {
16 | "build": "npx rollup -c .rollup.js",
17 | "build:watch": "npx rollup -c .rollup.js --watch",
18 | "lint": "npx eslint --cache src",
19 | "lint:fix": "npx eslint --cache --fix",
20 | "pretest": "npm install && npm run build",
21 | "test": "npm run lint && npm run tape",
22 | "tape": "npx postcss-tape",
23 | "prepublishOnly": "npm test"
24 | },
25 | "engines": {
26 | "node": ">=12"
27 | },
28 | "peerDependencies": {
29 | "postcss": "^8.3"
30 | },
31 | "dependencies": {
32 | "autoprefixer": "^10.4.0",
33 | "browserslist": "^4.17.5",
34 | "caniuse-lite": "^1.0.30001272",
35 | "css-blank-pseudo": "^2.0.0",
36 | "css-has-pseudo": "^2.0.0",
37 | "css-prefers-color-scheme": "^5.0.0",
38 | "cssdb": "^5.0.0",
39 | "postcss": "^8.3",
40 | "postcss-attribute-case-insensitive": "^5.0.0",
41 | "postcss-color-functional-notation": "^4.0.1",
42 | "postcss-color-hex-alpha": "^8.0.0",
43 | "postcss-color-rebeccapurple": "^7.0.0",
44 | "postcss-custom-media": "^8.0.0",
45 | "postcss-custom-properties": "^12.0.0",
46 | "postcss-custom-selectors": "^6.0.0",
47 | "postcss-dir-pseudo-class": "^6.0.0",
48 | "postcss-double-position-gradients": "^3.0.1",
49 | "postcss-env-function": "^4.0.2",
50 | "postcss-focus-visible": "^6.0.1",
51 | "postcss-focus-within": "^5.0.1",
52 | "postcss-font-variant": "^5.0.0",
53 | "postcss-gap-properties": "^3.0.0",
54 | "postcss-image-set-function": "^4.0.2",
55 | "postcss-initial": "^4.0.1",
56 | "postcss-lab-function": "^4.0.1",
57 | "postcss-logical": "^5.0.0",
58 | "postcss-media-minmax": "^5.0.0",
59 | "postcss-nesting": "^10.0.2",
60 | "postcss-overflow-shorthand": "^3.0.0",
61 | "postcss-page-break": "^3.0.4",
62 | "postcss-place": "^7.0.1",
63 | "postcss-pseudo-class-any-link": "^7.0.0",
64 | "postcss-replace-overflow-wrap": "^4.0.0",
65 | "postcss-selector-not": "^5.0.0"
66 | },
67 | "devDependencies": {
68 | "@babel/core": "^7.15.8",
69 | "@babel/preset-env": "^7.15.8",
70 | "eslint": "^8.1.0",
71 | "postcss-simple-vars": "^6.0.3",
72 | "postcss-tape": "^6.0.1",
73 | "pre-commit": "^1.2.2",
74 | "rollup": "^2.58.3",
75 | "rollup-plugin-babel": "^4.4.0"
76 | },
77 | "babel": {
78 | "presets": [
79 | [
80 | "@babel/env",
81 | {
82 | "targets": "maintained node versions"
83 | }
84 | ]
85 | ]
86 | },
87 | "eslintConfig": {
88 | "env": {
89 | "browser": true,
90 | "es6": true,
91 | "node": true
92 | },
93 | "extends": "eslint:recommended",
94 | "parserOptions": {
95 | "ecmaVersion": 2020,
96 | "sourceType": "module"
97 | },
98 | "root": true
99 | },
100 | "rollup": {
101 | "input": "src/postcss.js",
102 | "plugins": [
103 | "rollup-plugin-babel"
104 | ],
105 | "output": [
106 | {
107 | "exports": "default",
108 | "file": "dist/index.js",
109 | "format": "cjs"
110 | },
111 | {
112 | "file": "dist/index.mjs",
113 | "format": "esm"
114 | }
115 | ]
116 | },
117 | "keywords": [
118 | "postcss",
119 | "css",
120 | "postcss-plugin",
121 | "specifications",
122 | "specs",
123 | "features",
124 | "lists",
125 | "stages",
126 | "w3c",
127 | "csswg",
128 | "future",
129 | "next"
130 | ]
131 | }
132 |
--------------------------------------------------------------------------------
/src/cli.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import plugin from './postcss';
3 |
4 | if (process.argv.length < 3) {
5 | console.log([
6 | 'PostCSS Preset Env\n',
7 | ' Transforms Modern CSS\n',
8 | 'Usage:\n',
9 | ' postcss-preset-env source.css transformed.css',
10 | ' postcss-preset-env --in=source.css --out=transformed.css --opts={}',
11 | ' echo "/* a bunch of css */" | focus-within\n'
12 | ].join('\n'));
13 | process.exit(0);
14 | }
15 |
16 | // get process and plugin options from the command line
17 | const fileRegExp = /^[\w/.]+$/;
18 | const argRegExp = /^--(\w+)=("|')?(.+)\2$/;
19 | const relaxedJsonPropRegExp = /(['"])?([a-z0-9A-Z_]+)(['"])?:/g;
20 | const relaxedJsonValueRegExp = /("[a-z0-9A-Z_]+":\s*)(?!true|false|null|\d+)'?([A-z0-9]+)'?([,}])/g;
21 | const argo = process.argv.slice(2).reduce(
22 | (object, arg) => {
23 | const argMatch = arg.match(argRegExp);
24 | const fileMatch = arg.match(fileRegExp);
25 |
26 | if (argMatch) {
27 | object[argMatch[1]] = argMatch[3];
28 | } else if (fileMatch) {
29 | if (object.from === '') {
30 | object.from = arg;
31 | } else if (object.to === '') {
32 | object.to = arg;
33 | }
34 | }
35 |
36 | return object;
37 | },
38 | { from: '', to: '', opts: 'null' }
39 | );
40 |
41 | // get css from command line arguments or stdin
42 | (argo.from === '' ? getStdin() : readFile(argo.from))
43 | .then(css => {
44 | const pluginOpts = JSON.parse(
45 | argo.opts
46 | .replace(relaxedJsonPropRegExp, '"$2": ')
47 | .replace(relaxedJsonValueRegExp, '$1"$2"$3')
48 | );
49 | const processOptions = Object.assign({ from: argo.from, to: argo.to || argo.from }, argo.map ? { map: JSON.parse(argo.map) } : {});
50 |
51 | const result = plugin.process(css, processOptions, pluginOpts);
52 |
53 | if (argo.to === '') {
54 | return result.css;
55 | } else {
56 | return writeFile(argo.to, result.css).then(
57 | () => `CSS was written to "${argo.to}"`
58 | )
59 | }
60 | }).then(
61 | result => {
62 | console.log(result);
63 |
64 | process.exit(0);
65 | },
66 | error => {
67 | console.error(error);
68 |
69 | process.exit(1);
70 | }
71 | );
72 |
73 | function readFile(pathname) {
74 | return new Promise((resolve, reject) => {
75 | fs.readFile(pathname, 'utf8', (error, data) => {
76 | if (error) {
77 | reject(error);
78 | } else {
79 | resolve(data);
80 | }
81 | });
82 | });
83 | }
84 |
85 | function writeFile(pathname, data) {
86 | return new Promise((resolve, reject) => {
87 | fs.writeFile(pathname, data, (error, content) => {
88 | if (error) {
89 | reject(error);
90 | } else {
91 | resolve(content);
92 | }
93 | });
94 | });
95 | }
96 |
97 | function getStdin() {
98 | return new Promise(resolve => {
99 | let data = '';
100 |
101 | if (process.stdin.isTTY) {
102 | resolve(data);
103 | } else {
104 | process.stdin.setEncoding('utf8');
105 |
106 | process.stdin.on('readable', () => {
107 | let chunk;
108 |
109 | // eslint-disable-next-line no-cond-assign
110 | while (chunk = process.stdin.read()) {
111 | data += chunk;
112 | }
113 | });
114 |
115 | process.stdin.on('end', () => {
116 | resolve(data);
117 | });
118 | }
119 | });
120 | }
121 |
--------------------------------------------------------------------------------
/src/lib/get-transformed-insertions.js:
--------------------------------------------------------------------------------
1 | // return a list of features to be inserted before or after cssdb features
2 | export default function getTransformedInsertions(insertions, placement) {
3 | return Object.keys(insertions).map(
4 | id => [].concat(insertions[id]).map(
5 | plugin => ({
6 | [placement]: true,
7 | plugin,
8 | id
9 | })
10 | )
11 | ).reduce(
12 | (array, feature) => array.concat(feature), []
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/src/lib/get-unsupported-browsers-by-feature.js:
--------------------------------------------------------------------------------
1 | import * as caniuse from 'caniuse-lite';
2 |
3 | // return a list of browsers that do not support the feature
4 | export default function getUnsupportedBrowsersByFeature(feature) {
5 | const caniuseFeature = caniuse.features[feature];
6 |
7 | // if feature support can be determined
8 | if (caniuseFeature) {
9 | const stats = caniuse.feature(caniuseFeature).stats;
10 |
11 | // return an array of browsers and versions that do not support the feature
12 | const results = Object.keys(stats).reduce(
13 | (browsers, browser) => browsers.concat(
14 | Object.keys(stats[browser]).filter(
15 | version => stats[browser][version].indexOf('y') !== 0
16 | ).map(
17 | version => `${browser} ${version}`
18 | )
19 | ),
20 | []
21 | );
22 |
23 | return results;
24 | } else {
25 | // otherwise, return that the feature does not work in any browser
26 | return [ '> 0%' ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/lib/ids-by-execution-order.js:
--------------------------------------------------------------------------------
1 | // ids ordered by required execution, then alphabetically
2 | export default [
3 | 'custom-media-queries',
4 | 'custom-properties',
5 | 'environment-variables', // run environment-variables here to access transpiled custom media params and properties
6 | 'image-set-function', // run images-set-function before nesting-rules so that it may fix nested media
7 | 'media-query-ranges', // run media-query-range and
8 | 'prefers-color-scheme-query', // run prefers-color-scheme-query here to prevent duplicate transpilation after nesting-rules
9 | 'nesting-rules',
10 | 'custom-selectors', // run custom-selectors after nesting-rules to correctly transpile &:--custom-selector
11 | 'any-link-pseudo-class',
12 | 'case-insensitive-attributes',
13 | 'focus-visible-pseudo-class',
14 | 'focus-within-pseudo-class',
15 | 'matches-pseudo-class', // run matches-pseudo-class and
16 | 'not-pseudo-class', // run not-pseudo-class after other selectors have been transpiled
17 | 'logical-properties-and-values', // run logical-properties-and-values before dir-pseudo-class
18 | 'dir-pseudo-class',
19 | 'all-property', // run all-property before other property polyfills
20 | 'color-functional-notation',
21 | 'double-position-gradients',
22 | 'hexadecimal-alpha-notation',
23 | 'lab-function',
24 | 'rebeccapurple-color',
25 | 'color-mod-function', // run color-mod after other color modifications have finished
26 | 'blank-pseudo-class',
27 | 'break-properties',
28 | 'font-variant-property',
29 | 'has-pseudo-class',
30 | 'gap-properties',
31 | 'overflow-property',
32 | 'overflow-wrap-property',
33 | 'place-properties',
34 | 'system-ui-font-family'
35 | ];
36 |
--------------------------------------------------------------------------------
/src/lib/plugins-by-id.js:
--------------------------------------------------------------------------------
1 | import postcssAttributeCaseInsensitive from 'postcss-attribute-case-insensitive';
2 | import postcssBlankPseudo from 'css-blank-pseudo/postcss';
3 | import postcssColorFunctionalNotation from 'postcss-color-functional-notation';
4 | import postcssColorHexAlpha from 'postcss-color-hex-alpha';
5 | import postcssColorRebeccapurple from 'postcss-color-rebeccapurple';
6 | import postcssCustomMedia from 'postcss-custom-media';
7 | import postcssCustomProperties from 'postcss-custom-properties';
8 | import postcssCustomSelectors from 'postcss-custom-selectors';
9 | import postcssDirPseudoClass from 'postcss-dir-pseudo-class';
10 | import postcssDoublePositionGradients from 'postcss-double-position-gradients';
11 | import postcssEnvFunction from 'postcss-env-function';
12 | import postcssFocusVisible from 'postcss-focus-visible';
13 | import postcssFocusWithin from 'postcss-focus-within';
14 | import postcssFontVariant from 'postcss-font-variant';
15 | import postcssFontFamilySystemUi from '../patch/postcss-system-ui-font-family';
16 | import postcssGapProperties from 'postcss-gap-properties';
17 | import postcssHasPseudo from 'css-has-pseudo/postcss';
18 | import postcssImageSetPolyfill from 'postcss-image-set-function';
19 | import postcssInitial from 'postcss-initial';
20 | import postcssLabFunction from 'postcss-lab-function';
21 | import postcssLogical from 'postcss-logical';
22 | import postcssMediaMinmax from 'postcss-media-minmax';
23 | import postcssNesting from 'postcss-nesting';
24 | import postcssOverflowShorthand from 'postcss-overflow-shorthand';
25 | import postcssPageBreak from 'postcss-page-break';
26 | import postcssPlace from 'postcss-place';
27 | import postcssPrefersColorScheme from 'css-prefers-color-scheme/postcss';
28 | import postcssPseudoClassAnyLink from 'postcss-pseudo-class-any-link';
29 | import postcssReplaceOverflowWrap from 'postcss-replace-overflow-wrap';
30 | import postcssSelectorNot from 'postcss-selector-not';
31 |
32 | // postcss plugins ordered by id
33 | export default {
34 | 'all-property': postcssInitial,
35 | 'any-link-pseudo-class': postcssPseudoClassAnyLink,
36 | 'blank-pseudo-class': postcssBlankPseudo,
37 | 'break-properties': postcssPageBreak,
38 | 'case-insensitive-attributes': postcssAttributeCaseInsensitive,
39 | 'color-functional-notation': postcssColorFunctionalNotation,
40 | 'custom-media-queries': postcssCustomMedia,
41 | 'custom-properties': postcssCustomProperties,
42 | 'custom-selectors': postcssCustomSelectors,
43 | 'dir-pseudo-class': postcssDirPseudoClass,
44 | 'double-position-gradients': postcssDoublePositionGradients,
45 | 'environment-variables': postcssEnvFunction,
46 | 'focus-visible-pseudo-class': postcssFocusVisible,
47 | 'focus-within-pseudo-class': postcssFocusWithin,
48 | 'font-variant-property': postcssFontVariant,
49 | 'gap-properties': postcssGapProperties,
50 | 'has-pseudo-class': postcssHasPseudo,
51 | 'hexadecimal-alpha-notation': postcssColorHexAlpha,
52 | 'image-set-function': postcssImageSetPolyfill,
53 | 'lab-function': postcssLabFunction,
54 | 'logical-properties-and-values': postcssLogical,
55 | 'media-query-ranges': postcssMediaMinmax,
56 | 'nesting-rules': postcssNesting,
57 | 'not-pseudo-class': postcssSelectorNot,
58 | 'overflow-property': postcssOverflowShorthand,
59 | 'overflow-wrap-property': postcssReplaceOverflowWrap,
60 | 'place-properties': postcssPlace,
61 | 'prefers-color-scheme-query': postcssPrefersColorScheme,
62 | 'rebeccapurple-color': postcssColorRebeccapurple,
63 | 'system-ui-font-family': postcssFontFamilySystemUi
64 | };
65 |
--------------------------------------------------------------------------------
/src/lib/write-to-exports.js:
--------------------------------------------------------------------------------
1 | /* eslint max-params: ["error", 4] */
2 |
3 | import fs from 'fs';
4 | import path from 'path';
5 |
6 | /* Write Exports to CSS File
7 | /* ========================================================================== */
8 |
9 | function getCustomMediaAsCss(customMedia) {
10 | const cssContent = Object.keys(customMedia).reduce((cssLines, name) => {
11 | cssLines.push(`@custom-media ${name} ${customMedia[name]};`);
12 |
13 | return cssLines;
14 | }, []).join('\n');
15 | const css = `${cssContent}\n`;
16 |
17 | return css;
18 | }
19 |
20 | function getCustomPropertiesAsCss(customProperties) {
21 | const cssContent = Object.keys(customProperties).reduce((cssLines, name) => {
22 | cssLines.push(`\t${name}: ${customProperties[name]};`);
23 |
24 | return cssLines;
25 | }, []).join('\n');
26 | const css = `:root {\n${cssContent}\n}\n`;
27 |
28 | return css;
29 | }
30 |
31 | function getCustomSelectorsAsCss(customSelectors) {
32 | const cssContent = Object.keys(customSelectors).reduce((cssLines, name) => {
33 | cssLines.push(`@custom-selector ${name} ${customSelectors[name]};`);
34 |
35 | return cssLines;
36 | }, []).join('\n');
37 | const css = `${cssContent}\n`;
38 |
39 | return css;
40 | }
41 |
42 | async function writeExportsToCssFile(to, customMedia, customProperties, customSelectors) {
43 | const customPropertiesAsCss = getCustomPropertiesAsCss(customProperties);
44 | const customMediaAsCss = getCustomMediaAsCss(customMedia);
45 | const customSelectorsAsCss = getCustomSelectorsAsCss(customSelectors);
46 | const css = `${customMediaAsCss}\n${customSelectorsAsCss}\n${customPropertiesAsCss}`;
47 |
48 | await writeFile(to, css);
49 | }
50 |
51 | /* Write Exports to JSON file
52 | /* ========================================================================== */
53 |
54 | async function writeExportsToJsonFile(to, customMedia, customProperties, customSelectors) {
55 | const jsonContent = JSON.stringify({
56 | 'custom-media': customMedia,
57 | 'custom-properties': customProperties,
58 | 'custom-selectors': customSelectors
59 | }, null, ' ');
60 | const json = `${jsonContent}\n`;
61 |
62 | await writeFile(to, json);
63 | }
64 |
65 | /* Write Exports to Common JS file
66 | /* ========================================================================== */
67 |
68 | function getObjectWithKeyAsCjs(key, object) {
69 | const jsContents = Object.keys(object).reduce((jsLines, name) => {
70 | jsLines.push(`\t\t'${escapeForJS(name)}': '${escapeForJS(object[name])}'`);
71 |
72 | return jsLines;
73 | }, []).join(',\n');
74 | const cjs = `\n\t${key}: {\n${jsContents}\n\t}`;
75 |
76 | return cjs;
77 | }
78 |
79 | async function writeExportsToCjsFile(to, customMedia, customProperties, customSelectors) {
80 | const customMediaAsCjs = getObjectWithKeyAsCjs('customMedia', customMedia);
81 | const customPropertiesAsCjs = getObjectWithKeyAsCjs('customProperties', customProperties);
82 | const customSelectorsAsCjs = getObjectWithKeyAsCjs('customSelectors', customSelectors);
83 | const cjs = `module.exports = {${customMediaAsCjs},${customPropertiesAsCjs},${customSelectorsAsCjs}\n};\n`;
84 |
85 | await writeFile(to, cjs);
86 | }
87 |
88 | /* Write Exports to Module JS file
89 | /* ========================================================================== */
90 |
91 | function getObjectWithKeyAsMjs(key, object) {
92 | const mjsContents = Object.keys(object).reduce((mjsLines, name) => {
93 | mjsLines.push(`\t'${escapeForJS(name)}': '${escapeForJS(object[name])}'`);
94 |
95 | return mjsLines;
96 | }, []).join(',\n');
97 | const mjs = `export const ${key} = {\n${mjsContents}\n};\n`;
98 |
99 | return mjs;
100 | }
101 |
102 | async function writeExportsToMjsFile(to, customMedia, customProperties, customSelectors) {
103 | const customMediaAsMjs = getObjectWithKeyAsMjs('customMedia', customMedia);
104 | const customPropertiesAsMjs = getObjectWithKeyAsMjs('customProperties', customProperties);
105 | const customSelectorsAsMjs = getObjectWithKeyAsMjs('customSelectors', customSelectors);
106 | const mjs = `${customMediaAsMjs}\n${customPropertiesAsMjs}\n${customSelectorsAsMjs}`;
107 |
108 | await writeFile(to, mjs);
109 | }
110 |
111 | /* Write Exports to Exports
112 | /* ========================================================================== */
113 |
114 | export default function writeToExports(customExports, destinations) {
115 | return Promise.all([].concat(destinations).map(async destination => {
116 | if (destination instanceof Function) {
117 | await destination({
118 | customMedia: getObjectWithStringifiedKeys(customExports.customMedia),
119 | customProperties: getObjectWithStringifiedKeys(customExports.customProperties),
120 | customSelectors: getObjectWithStringifiedKeys(customExports.customSelectors)
121 | });
122 | } else {
123 | // read the destination as an object
124 | const opts = destination === Object(destination) ? destination : { to: String(destination) };
125 |
126 | // transformer for Exports into a JSON-compatible object
127 | const toJSON = opts.toJSON || getObjectWithStringifiedKeys;
128 |
129 | if ('customMedia' in opts || 'customProperties' in opts || 'customSelectors' in opts) {
130 | // write directly to an object as customProperties
131 | opts.customMedia = toJSON(customExports.customMedia);
132 | opts.customProperties = toJSON(customExports.customProperties);
133 | opts.customSelectors = toJSON(customExports.customSelectors);
134 | } else if ('custom-media' in opts || 'custom-properties' in opts || 'custom-selectors' in opts) {
135 | // write directly to an object as custom-properties
136 | opts['custom-media'] = toJSON(customExports.customMedia);
137 | opts['custom-properties'] = toJSON(customExports.customProperties);
138 | opts['custom-selectors'] = toJSON(customExports.customSelectors);
139 | } else {
140 | // destination pathname
141 | const to = String(opts.to || '');
142 |
143 | // type of file being written to
144 | const type = (opts.type || path.extname(opts.to).slice(1)).toLowerCase();
145 |
146 | // transformed Exports
147 | const customMediaJSON = toJSON(customExports.customMedia);
148 | const customPropertiesJSON = toJSON(customExports.customProperties);
149 | const customSelectorsJSON = toJSON(customExports.customSelectors);
150 |
151 | if (type === 'css') {
152 | await writeExportsToCssFile(to, customMediaJSON, customPropertiesJSON, customSelectorsJSON);
153 | }
154 |
155 | if (type === 'js') {
156 | await writeExportsToCjsFile(to, customMediaJSON, customPropertiesJSON, customSelectorsJSON);
157 | }
158 |
159 | if (type === 'json') {
160 | await writeExportsToJsonFile(to, customMediaJSON, customPropertiesJSON, customSelectorsJSON);
161 | }
162 |
163 | if (type === 'mjs') {
164 | await writeExportsToMjsFile(to, customMediaJSON, customPropertiesJSON, customSelectorsJSON);
165 | }
166 | }
167 | }
168 | }));
169 | }
170 |
171 | /* Helper utilities
172 | /* ========================================================================== */
173 |
174 | function getObjectWithStringifiedKeys(object) {
175 | return Object.keys(object).reduce((objectJSON, key) => {
176 | objectJSON[key] = String(object[key]);
177 |
178 | return objectJSON;
179 | }, {});
180 | }
181 |
182 | function writeFile(to, text) {
183 | return new Promise((resolve, reject) => {
184 | fs.writeFile(to, text, error => {
185 | if (error) {
186 | reject(error);
187 | } else {
188 | resolve();
189 | }
190 | });
191 | });
192 | }
193 |
194 | function escapeForJS(string) {
195 | return string.replace(/\\([\s\S])|(')/g, '\\$1$2').replace(/\n/g, '\\n').replace(/\r/g, '\\r');
196 | }
197 |
--------------------------------------------------------------------------------
/src/patch/postcss-system-ui-font-family.js:
--------------------------------------------------------------------------------
1 | export default function postcssSystemUiFont() {
2 | return {
3 | postcssPlugin: 'postcss-system-ui-font',
4 | Declaration(/** @type {import('postcss').Declaration} */ node) {
5 | if (propertyRegExp.test(node.prop)) {
6 | if (!node.value.includes(systemUiFamily.join(', '))) {
7 | node.value = node.value.replace(systemUiMatch, systemUiReplace);
8 | }
9 | }
10 | }
11 | }
12 | }
13 |
14 | postcssSystemUiFont.postcss = true;
15 |
16 | const propertyRegExp = /(?:^(?:-|\\002d){2})|(?:^font(?:-family)?$)/i;
17 | const whitespace = '[\\f\\n\\r\\x09\\x20]';
18 | const systemUiFamily = [
19 | 'system-ui',
20 | /* macOS 10.11-10.12 */ '-apple-system',
21 | /* Windows 6+ */ 'Segoe UI',
22 | /* Android 4+ */ 'Roboto',
23 | /* Ubuntu 10.10+ */ 'Ubuntu',
24 | /* Gnome 3+ */ 'Cantarell',
25 | /* KDE Plasma 5+ */ 'Noto Sans',
26 | /* fallback */ 'sans-serif'
27 | ];
28 | const systemUiMatch = new RegExp(`(^|,|${whitespace}+)(?:system-ui${whitespace}*)(?:,${whitespace}*(?:${systemUiFamily.join('|')})${whitespace}*)?(,|$)`, 'i');
29 | const systemUiReplace = `$1${systemUiFamily.join(', ')}$2`;
30 |
--------------------------------------------------------------------------------
/src/postcss.js:
--------------------------------------------------------------------------------
1 | import autoprefixer from 'autoprefixer';
2 | import browserslist from 'browserslist';
3 | import cssdb from 'cssdb';
4 | import plugins from './lib/plugins-by-id';
5 | import getTransformedInsertions from './lib/get-transformed-insertions';
6 | import getUnsupportedBrowsersByFeature from './lib/get-unsupported-browsers-by-feature';
7 | import idsByExecutionOrder from './lib/ids-by-execution-order';
8 | import writeToExports from './lib/write-to-exports';
9 |
10 | const plugin = opts => {
11 | // initialize options
12 | const features = Object(Object(opts).features);
13 | const insertBefore = Object(Object(opts).insertBefore);
14 | const insertAfter = Object(Object(opts).insertAfter);
15 | const browsers = Object(opts).browsers;
16 | const stage = 'stage' in Object(opts)
17 | ? opts.stage === false
18 | ? 5
19 | : parseInt(opts.stage) || 0
20 | : 2;
21 | const autoprefixerOptions = Object(opts).autoprefixer;
22 | const sharedOpts = initializeSharedOpts(Object(opts));
23 | const stagedAutoprefixer = autoprefixerOptions === false
24 | ? () => {}
25 | : autoprefixer(Object.assign({ overrideBrowserslist: browsers }, autoprefixerOptions));
26 |
27 | // polyfillable features (those with an available postcss plugin)
28 | const polyfillableFeatures = cssdb.concat(
29 | // additional features to be inserted before cssdb features
30 | getTransformedInsertions(insertBefore, 'insertBefore'),
31 | // additional features to be inserted after cssdb features
32 | getTransformedInsertions(insertAfter, 'insertAfter')
33 | ).filter(
34 | // inserted features or features with an available postcss plugin
35 | feature => feature.insertBefore || feature.id in plugins
36 | ).sort(
37 | // features sorted by execution order and then insertion order
38 | (a, b) => idsByExecutionOrder.indexOf(a.id) - idsByExecutionOrder.indexOf(b.id) || (a.insertBefore ? -1 : b.insertBefore ? 1 : 0) || (a.insertAfter ? 1 : b.insertAfter ? -1 : 0)
39 | ).map(
40 | // polyfillable features as an object
41 | feature => {
42 | // target browsers for the polyfill
43 | const unsupportedBrowsers = getUnsupportedBrowsersByFeature(feature.caniuse);
44 |
45 | return feature.insertBefore || feature.insertAfter ? {
46 | browsers: unsupportedBrowsers,
47 | plugin: feature.plugin,
48 | id: `${feature.insertBefore ? 'before' : 'after'}-${feature.id}`,
49 | stage: 6
50 | } : {
51 | browsers: unsupportedBrowsers,
52 | plugin: plugins[feature.id],
53 | id: feature.id,
54 | stage: feature.stage
55 | };
56 | }
57 | );
58 |
59 | // staged features (those at or above the selected stage)
60 | const stagedFeatures = polyfillableFeatures.filter(
61 | feature => feature.id in features
62 | ? features[feature.id]
63 | : feature.stage >= stage
64 | ).map(
65 | feature => {
66 | let options;
67 | let plugin;
68 |
69 | if (features[feature.id] === true) {
70 | // if the plugin is enabled
71 | options = sharedOpts ? Object.assign({}, sharedOpts) : undefined;
72 | } else {
73 | options = sharedOpts
74 | // if the plugin has shared options and individual options
75 | ? Object.assign({}, sharedOpts, features[feature.id])
76 | // if the plugin has individual options
77 | : Object.assign({}, features[feature.id]);
78 | }
79 |
80 | if (feature.plugin.postcss) {
81 | plugin = feature.plugin(options);
82 | } else {
83 | plugin = feature.plugin;
84 | }
85 |
86 | return {
87 | browsers: feature.browsers,
88 | plugin,
89 | id: feature.id
90 | };
91 | }
92 | );
93 |
94 | // browsers supported by the configuration
95 | const supportedBrowsers = browserslist(browsers, { ignoreUnknownVersions: true });
96 |
97 | // features supported by the stage and browsers
98 | const supportedFeatures = stagedFeatures.filter(
99 | feature => feature.id in features
100 | ? features[feature.id]
101 | : supportedBrowsers.some(
102 | supportedBrowser => browserslist(feature.browsers, {
103 | ignoreUnknownVersions: true
104 | }).some(
105 | polyfillBrowser => polyfillBrowser === supportedBrowser
106 | )
107 | )
108 | );
109 |
110 | const usedPlugins = supportedFeatures.map(feature => feature.plugin);
111 | usedPlugins.push(stagedAutoprefixer);
112 |
113 | return {
114 | postcssPlugin: 'postcss-preset-env',
115 | plugins: usedPlugins,
116 | OnceExit: function() {
117 | if ( Object( opts ).exportTo ) {
118 | writeToExports( sharedOpts.exportTo, opts.exportTo );
119 | }
120 | }
121 | };
122 | }
123 |
124 | const initializeSharedOpts = opts => {
125 | if ('importFrom' in opts || 'exportTo' in opts || 'preserve' in opts) {
126 | const sharedOpts = {};
127 |
128 | if ('importFrom' in opts) {
129 | sharedOpts.importFrom = opts.importFrom;
130 | }
131 |
132 | if ('exportTo' in opts) {
133 | sharedOpts.exportTo = {
134 | customMedia: {},
135 | customProperties: {},
136 | customSelectors: {},
137 | };
138 | }
139 |
140 | if ('preserve' in opts) {
141 | sharedOpts.preserve = opts.preserve;
142 | }
143 |
144 | return sharedOpts;
145 | }
146 |
147 | return false;
148 | };
149 |
150 | plugin.postcss = true;
151 |
152 | export default plugin;
153 |
--------------------------------------------------------------------------------
/test/basic.autoprefixer.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: 1;
7 | order: var(--order);
8 | }
9 |
10 | .test-image-set-function {
11 | background-image: url(img/test.png);
12 | }
13 |
14 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
15 |
16 | .test-image-set-function {
17 | background-image: url(img/test-2x.png);
18 | }
19 | }
20 |
21 | .test-image-set-function {
22 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
23 | order: 2;
24 | }
25 |
26 | [dir="ltr"] .test-logical-properties-and-values {
27 | margin: 1px 4px 3px 2px;
28 | }
29 |
30 | [dir="rtl"] .test-logical-properties-and-values {
31 | margin: 1px 2px 3px 4px;
32 | }
33 |
34 | .test-logical-properties-and-values {
35 | order: 3;
36 | padding-top: 5px;
37 | padding-bottom: 5px;
38 | }
39 |
40 | .test-nesting-rules {
41 | order: 4;
42 |
43 | & p {
44 | order: 5;
45 | }
46 |
47 | order: 6;
48 | }
49 |
50 | @custom-media --narrow-window (max-width: 30em);
51 |
52 | @media (--narrow-window) {
53 | .test-custom-media-queries {
54 | order: 7;
55 | }
56 | }
57 |
58 | @media (min-width: 480px) and (max-width: 767px) {
59 | .test-media-query-ranges {
60 | order: 8;
61 | }
62 | }
63 |
64 | @custom-media --dark-mode (prefers-color-scheme: dark);
65 |
66 | @media (--dark-mode) {
67 | body {
68 | background-color: black;
69 | color: white;
70 | }
71 | }
72 |
73 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
74 |
75 | .test-custom-selectors:--heading {
76 | order: 9;
77 | }
78 |
79 | .test-case-insensitive-attributes[frame=hsides],.test-case-insensitive-attributes[frame=Hsides],.test-case-insensitive-attributes[frame=hSides],.test-case-insensitive-attributes[frame=HSides],.test-case-insensitive-attributes[frame=hsIdes],.test-case-insensitive-attributes[frame=HsIdes],.test-case-insensitive-attributes[frame=hSIdes],.test-case-insensitive-attributes[frame=HSIdes],.test-case-insensitive-attributes[frame=hsiDes],.test-case-insensitive-attributes[frame=HsiDes],.test-case-insensitive-attributes[frame=hSiDes],.test-case-insensitive-attributes[frame=HSiDes],.test-case-insensitive-attributes[frame=hsIDes],.test-case-insensitive-attributes[frame=HsIDes],.test-case-insensitive-attributes[frame=hSIDes],.test-case-insensitive-attributes[frame=HSIDes],.test-case-insensitive-attributes[frame=hsidEs],.test-case-insensitive-attributes[frame=HsidEs],.test-case-insensitive-attributes[frame=hSidEs],.test-case-insensitive-attributes[frame=HSidEs],.test-case-insensitive-attributes[frame=hsIdEs],.test-case-insensitive-attributes[frame=HsIdEs],.test-case-insensitive-attributes[frame=hSIdEs],.test-case-insensitive-attributes[frame=HSIdEs],.test-case-insensitive-attributes[frame=hsiDEs],.test-case-insensitive-attributes[frame=HsiDEs],.test-case-insensitive-attributes[frame=hSiDEs],.test-case-insensitive-attributes[frame=HSiDEs],.test-case-insensitive-attributes[frame=hsIDEs],.test-case-insensitive-attributes[frame=HsIDEs],.test-case-insensitive-attributes[frame=hSIDEs],.test-case-insensitive-attributes[frame=HSIDEs],.test-case-insensitive-attributes[frame=hsideS],.test-case-insensitive-attributes[frame=HsideS],.test-case-insensitive-attributes[frame=hSideS],.test-case-insensitive-attributes[frame=HSideS],.test-case-insensitive-attributes[frame=hsIdeS],.test-case-insensitive-attributes[frame=HsIdeS],.test-case-insensitive-attributes[frame=hSIdeS],.test-case-insensitive-attributes[frame=HSIdeS],.test-case-insensitive-attributes[frame=hsiDeS],.test-case-insensitive-attributes[frame=HsiDeS],.test-case-insensitive-attributes[frame=hSiDeS],.test-case-insensitive-attributes[frame=HSiDeS],.test-case-insensitive-attributes[frame=hsIDeS],.test-case-insensitive-attributes[frame=HsIDeS],.test-case-insensitive-attributes[frame=hSIDeS],.test-case-insensitive-attributes[frame=HSIDeS],.test-case-insensitive-attributes[frame=hsidES],.test-case-insensitive-attributes[frame=HsidES],.test-case-insensitive-attributes[frame=hSidES],.test-case-insensitive-attributes[frame=HSidES],.test-case-insensitive-attributes[frame=hsIdES],.test-case-insensitive-attributes[frame=HsIdES],.test-case-insensitive-attributes[frame=hSIdES],.test-case-insensitive-attributes[frame=HSIdES],.test-case-insensitive-attributes[frame=hsiDES],.test-case-insensitive-attributes[frame=HsiDES],.test-case-insensitive-attributes[frame=hSiDES],.test-case-insensitive-attributes[frame=HSiDES],.test-case-insensitive-attributes[frame=hsIDES],.test-case-insensitive-attributes[frame=HsIDES],.test-case-insensitive-attributes[frame=hSIDES],.test-case-insensitive-attributes[frame=HSIDES] {
80 | order: 10;
81 | }
82 |
83 | .test-rebeccapurple-color {
84 | color: #639;
85 | order: 11;
86 | }
87 |
88 | .test-hexadecimal-alpha-notation {
89 | background-color: rgba(243,243,243,0.95294);
90 | color: rgba(0,0,0,0.2);
91 | order: 12;
92 | }
93 |
94 | .test-color-functional-notation {
95 | color: rgb(70% 13.5% 13.5% / 50%);
96 | order: 13;
97 | }
98 |
99 | .test-lab-function {
100 | background-color: rgb(178, 34, 34);
101 | color: rgba(178, 34, 34, 0.5);
102 | order: 14;
103 | }
104 |
105 | .test-system-ui-font-family {
106 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
107 | order: 15;
108 | }
109 |
110 | .test-font-variant-property {
111 | font-feature-settings: "smcp";
112 | font-variant-caps: small-caps;
113 | order: 16;
114 | }
115 |
116 | .test-all-property {
117 | animation: none 0s ease 0s 1 normal none running;
118 | backface-visibility: visible;
119 | background: transparent none repeat 0 0 / auto auto padding-box border-box scroll;
120 | border: medium none currentColor;
121 | border-collapse: separate;
122 | border-image: none;
123 | border-radius: 0;
124 | border-spacing: 0;
125 | bottom: auto;
126 | box-shadow: none;
127 | box-sizing: content-box;
128 | caption-side: top;
129 | clear: none;
130 | clip: auto;
131 | color: #000;
132 | columns: auto;
133 | column-count: auto;
134 | column-fill: balance;
135 | column-gap: normal;
136 | column-rule: medium none currentColor;
137 | column-span: 1;
138 | column-width: auto;
139 | content: normal;
140 | counter-increment: none;
141 | counter-reset: none;
142 | cursor: auto;
143 | direction: ltr;
144 | display: inline;
145 | empty-cells: show;
146 | float: none;
147 | font-family: serif;
148 | font-size: medium;
149 | font-style: normal;
150 | font-variant: normal;
151 | font-weight: normal;
152 | font-stretch: normal;
153 | line-height: normal;
154 | height: auto;
155 | hyphens: none;
156 | left: auto;
157 | letter-spacing: normal;
158 | list-style: disc outside none;
159 | margin: 0;
160 | max-height: none;
161 | max-width: none;
162 | min-height: 0;
163 | min-width: 0;
164 | opacity: 1;
165 | orphans: 2;
166 | outline: medium none invert;
167 | overflow: visible;
168 | overflow-x: visible;
169 | overflow-y: visible;
170 | padding: 0;
171 | page-break-after: auto;
172 | page-break-before: auto;
173 | page-break-inside: auto;
174 | perspective: none;
175 | perspective-origin: 50% 50%;
176 | position: static;
177 | right: auto;
178 | tab-size: 8;
179 | table-layout: auto;
180 | text-align: left;
181 | text-align-last: auto;
182 | text-decoration: none;
183 | text-indent: 0;
184 | text-shadow: none;
185 | text-transform: none;
186 | top: auto;
187 | transform: none;
188 | transform-origin: 50% 50% 0;
189 | transform-style: flat;
190 | transition: none 0s ease 0s;
191 | unicode-bidi: normal;
192 | vertical-align: baseline;
193 | visibility: visible;
194 | white-space: normal;
195 | widows: 2;
196 | width: auto;
197 | word-spacing: normal;
198 | z-index: auto;
199 | all: initial;
200 | order: 17;
201 | }
202 |
203 | .test-matches-pseudo-class:matches(:first-child, .special) {
204 | order: 18;
205 | }
206 |
207 | .test-not-pseudo-class:not(:first-child):not(.special) {
208 | order: 19;
209 | }
210 |
211 | .test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited {
212 | order: 20;
213 | }
214 |
215 | .test-any-link-pseudo-class:any-link {
216 | order: 20;
217 | }
218 |
219 | [dir="rtl"] .test-dir-pseudo-class {
220 | order: 21;
221 | }
222 |
223 | .test-overflow-wrap-property {
224 | order: 22;
225 | word-wrap: break-word;
226 | }
227 |
228 | .test-focus-visible-pseudo-class.focus-visible {
229 | order: 23;
230 | }
231 |
232 | .test-focus-visible-pseudo-class:focus-visible {
233 | order: 23;
234 | }
235 |
236 | .test-double-position-gradients {
237 | background-image: conic-gradient(yellowgreen 40%, gold 0deg, gold 75%, #f06 0deg);
238 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
239 | }
240 |
241 | .test-blank-pseudo-class:blank {
242 | background-color: yellow;
243 | }
244 |
245 | .test-has-pseudo-class[\:has\(.inner-class\)] {
246 | background-color: yellow;
247 | }
248 |
249 | .test-has-pseudo-class:has(.inner-class) {
250 | background-color: yellow;
251 | }
252 |
--------------------------------------------------------------------------------
/test/basic.autoprefixer.false.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: 1;
7 | order: var(--order);
8 | }
9 |
10 | .test-image-set-function {
11 | background-image: url(img/test.png);
12 | }
13 |
14 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
15 |
16 | .test-image-set-function {
17 | background-image: url(img/test-2x.png);
18 | }
19 | }
20 |
21 | .test-image-set-function {
22 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
23 | order: 2;
24 | }
25 |
26 | [dir="ltr"] .test-logical-properties-and-values {
27 | margin: 1px 4px 3px 2px;
28 | }
29 |
30 | [dir="rtl"] .test-logical-properties-and-values {
31 | margin: 1px 2px 3px 4px;
32 | }
33 |
34 | .test-logical-properties-and-values {
35 | order: 3;
36 | padding-top: 5px;
37 | padding-bottom: 5px;
38 | }
39 |
40 | .test-nesting-rules {
41 | order: 4;
42 |
43 | & p {
44 | order: 5;
45 | }
46 |
47 | order: 6;
48 | }
49 |
50 | @custom-media --narrow-window (max-width: 30em);
51 |
52 | @media (--narrow-window) {
53 | .test-custom-media-queries {
54 | order: 7;
55 | }
56 | }
57 |
58 | @media (min-width: 480px) and (max-width: 767px) {
59 | .test-media-query-ranges {
60 | order: 8;
61 | }
62 | }
63 |
64 | @custom-media --dark-mode (prefers-color-scheme: dark);
65 |
66 | @media (--dark-mode) {
67 | body {
68 | background-color: black;
69 | color: white;
70 | }
71 | }
72 |
73 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
74 |
75 | .test-custom-selectors:--heading {
76 | order: 9;
77 | }
78 |
79 | .test-case-insensitive-attributes[frame=hsides],.test-case-insensitive-attributes[frame=Hsides],.test-case-insensitive-attributes[frame=hSides],.test-case-insensitive-attributes[frame=HSides],.test-case-insensitive-attributes[frame=hsIdes],.test-case-insensitive-attributes[frame=HsIdes],.test-case-insensitive-attributes[frame=hSIdes],.test-case-insensitive-attributes[frame=HSIdes],.test-case-insensitive-attributes[frame=hsiDes],.test-case-insensitive-attributes[frame=HsiDes],.test-case-insensitive-attributes[frame=hSiDes],.test-case-insensitive-attributes[frame=HSiDes],.test-case-insensitive-attributes[frame=hsIDes],.test-case-insensitive-attributes[frame=HsIDes],.test-case-insensitive-attributes[frame=hSIDes],.test-case-insensitive-attributes[frame=HSIDes],.test-case-insensitive-attributes[frame=hsidEs],.test-case-insensitive-attributes[frame=HsidEs],.test-case-insensitive-attributes[frame=hSidEs],.test-case-insensitive-attributes[frame=HSidEs],.test-case-insensitive-attributes[frame=hsIdEs],.test-case-insensitive-attributes[frame=HsIdEs],.test-case-insensitive-attributes[frame=hSIdEs],.test-case-insensitive-attributes[frame=HSIdEs],.test-case-insensitive-attributes[frame=hsiDEs],.test-case-insensitive-attributes[frame=HsiDEs],.test-case-insensitive-attributes[frame=hSiDEs],.test-case-insensitive-attributes[frame=HSiDEs],.test-case-insensitive-attributes[frame=hsIDEs],.test-case-insensitive-attributes[frame=HsIDEs],.test-case-insensitive-attributes[frame=hSIDEs],.test-case-insensitive-attributes[frame=HSIDEs],.test-case-insensitive-attributes[frame=hsideS],.test-case-insensitive-attributes[frame=HsideS],.test-case-insensitive-attributes[frame=hSideS],.test-case-insensitive-attributes[frame=HSideS],.test-case-insensitive-attributes[frame=hsIdeS],.test-case-insensitive-attributes[frame=HsIdeS],.test-case-insensitive-attributes[frame=hSIdeS],.test-case-insensitive-attributes[frame=HSIdeS],.test-case-insensitive-attributes[frame=hsiDeS],.test-case-insensitive-attributes[frame=HsiDeS],.test-case-insensitive-attributes[frame=hSiDeS],.test-case-insensitive-attributes[frame=HSiDeS],.test-case-insensitive-attributes[frame=hsIDeS],.test-case-insensitive-attributes[frame=HsIDeS],.test-case-insensitive-attributes[frame=hSIDeS],.test-case-insensitive-attributes[frame=HSIDeS],.test-case-insensitive-attributes[frame=hsidES],.test-case-insensitive-attributes[frame=HsidES],.test-case-insensitive-attributes[frame=hSidES],.test-case-insensitive-attributes[frame=HSidES],.test-case-insensitive-attributes[frame=hsIdES],.test-case-insensitive-attributes[frame=HsIdES],.test-case-insensitive-attributes[frame=hSIdES],.test-case-insensitive-attributes[frame=HSIdES],.test-case-insensitive-attributes[frame=hsiDES],.test-case-insensitive-attributes[frame=HsiDES],.test-case-insensitive-attributes[frame=hSiDES],.test-case-insensitive-attributes[frame=HSiDES],.test-case-insensitive-attributes[frame=hsIDES],.test-case-insensitive-attributes[frame=HsIDES],.test-case-insensitive-attributes[frame=hSIDES],.test-case-insensitive-attributes[frame=HSIDES] {
80 | order: 10;
81 | }
82 |
83 | .test-rebeccapurple-color {
84 | color: #639;
85 | order: 11;
86 | }
87 |
88 | .test-hexadecimal-alpha-notation {
89 | background-color: rgba(243,243,243,0.95294);
90 | color: rgba(0,0,0,0.2);
91 | order: 12;
92 | }
93 |
94 | .test-color-functional-notation {
95 | color: rgb(70% 13.5% 13.5% / 50%);
96 | order: 13;
97 | }
98 |
99 | .test-lab-function {
100 | background-color: rgb(178, 34, 34);
101 | color: rgba(178, 34, 34, 0.5);
102 | order: 14;
103 | }
104 |
105 | .test-system-ui-font-family {
106 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
107 | order: 15;
108 | }
109 |
110 | .test-font-variant-property {
111 | font-feature-settings: "smcp";
112 | font-variant-caps: small-caps;
113 | order: 16;
114 | }
115 |
116 | .test-all-property {
117 | animation: none 0s ease 0s 1 normal none running;
118 | backface-visibility: visible;
119 | background: transparent none repeat 0 0 / auto auto padding-box border-box scroll;
120 | border: medium none currentColor;
121 | border-collapse: separate;
122 | border-image: none;
123 | border-radius: 0;
124 | border-spacing: 0;
125 | bottom: auto;
126 | box-shadow: none;
127 | box-sizing: content-box;
128 | caption-side: top;
129 | clear: none;
130 | clip: auto;
131 | color: #000;
132 | columns: auto;
133 | column-count: auto;
134 | column-fill: balance;
135 | column-gap: normal;
136 | column-rule: medium none currentColor;
137 | column-span: 1;
138 | column-width: auto;
139 | content: normal;
140 | counter-increment: none;
141 | counter-reset: none;
142 | cursor: auto;
143 | direction: ltr;
144 | display: inline;
145 | empty-cells: show;
146 | float: none;
147 | font-family: serif;
148 | font-size: medium;
149 | font-style: normal;
150 | font-variant: normal;
151 | font-weight: normal;
152 | font-stretch: normal;
153 | line-height: normal;
154 | height: auto;
155 | hyphens: none;
156 | left: auto;
157 | letter-spacing: normal;
158 | list-style: disc outside none;
159 | margin: 0;
160 | max-height: none;
161 | max-width: none;
162 | min-height: 0;
163 | min-width: 0;
164 | opacity: 1;
165 | orphans: 2;
166 | outline: medium none invert;
167 | overflow: visible;
168 | overflow-x: visible;
169 | overflow-y: visible;
170 | padding: 0;
171 | page-break-after: auto;
172 | page-break-before: auto;
173 | page-break-inside: auto;
174 | perspective: none;
175 | perspective-origin: 50% 50%;
176 | position: static;
177 | right: auto;
178 | tab-size: 8;
179 | table-layout: auto;
180 | text-align: left;
181 | text-align-last: auto;
182 | text-decoration: none;
183 | text-indent: 0;
184 | text-shadow: none;
185 | text-transform: none;
186 | top: auto;
187 | transform: none;
188 | transform-origin: 50% 50% 0;
189 | transform-style: flat;
190 | transition: none 0s ease 0s;
191 | unicode-bidi: normal;
192 | vertical-align: baseline;
193 | visibility: visible;
194 | white-space: normal;
195 | widows: 2;
196 | width: auto;
197 | word-spacing: normal;
198 | z-index: auto;
199 | all: initial;
200 | order: 17;
201 | }
202 |
203 | .test-matches-pseudo-class:matches(:first-child, .special) {
204 | order: 18;
205 | }
206 |
207 | .test-not-pseudo-class:not(:first-child):not(.special) {
208 | order: 19;
209 | }
210 |
211 | .test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited {
212 | order: 20;
213 | }
214 |
215 | .test-any-link-pseudo-class:any-link {
216 | order: 20;
217 | }
218 |
219 | [dir="rtl"] .test-dir-pseudo-class {
220 | order: 21;
221 | }
222 |
223 | .test-overflow-wrap-property {
224 | order: 22;
225 | word-wrap: break-word;
226 | }
227 |
228 | .test-focus-visible-pseudo-class.focus-visible {
229 | order: 23;
230 | }
231 |
232 | .test-focus-visible-pseudo-class:focus-visible {
233 | order: 23;
234 | }
235 |
236 | .test-double-position-gradients {
237 | background-image: conic-gradient(yellowgreen 40%, gold 0deg, gold 75%, #f06 0deg);
238 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
239 | }
240 |
241 | .test-blank-pseudo-class:blank {
242 | background-color: yellow;
243 | }
244 |
245 | .test-has-pseudo-class[\:has\(.inner-class\)] {
246 | background-color: yellow;
247 | }
248 |
249 | .test-has-pseudo-class:has(.inner-class) {
250 | background-color: yellow;
251 | }
252 |
--------------------------------------------------------------------------------
/test/basic.ch38.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: 1;
7 | order: var(--order);
8 | }
9 |
10 | .test-image-set-function {
11 | background-image: url(img/test.png);
12 | }
13 |
14 | @media (min-resolution: 192dpi) {
15 |
16 | .test-image-set-function {
17 | background-image: url(img/test-2x.png);
18 | }
19 | }
20 |
21 | .test-image-set-function {
22 | background-image: -webkit-image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
23 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
24 | order: 2;
25 | }
26 |
27 | [dir="ltr"] .test-logical-properties-and-values {
28 | margin: 1px 4px 3px 2px;
29 | }
30 |
31 | [dir="rtl"] .test-logical-properties-and-values {
32 | margin: 1px 2px 3px 4px;
33 | }
34 |
35 | .test-logical-properties-and-values {
36 | order: 3;
37 | padding-top: 5px;
38 | padding-bottom: 5px;
39 | }
40 |
41 | .test-nesting-rules {
42 | order: 4;
43 |
44 | & p {
45 | order: 5;
46 | }
47 |
48 | order: 6;
49 | }
50 |
51 | @custom-media --narrow-window (max-width: 30em);
52 |
53 | @media (--narrow-window) {
54 | .test-custom-media-queries {
55 | order: 7;
56 | }
57 | }
58 |
59 | @media (min-width: 480px) and (max-width: 767px) {
60 | .test-media-query-ranges {
61 | order: 8;
62 | }
63 | }
64 |
65 | @custom-media --dark-mode (prefers-color-scheme: dark);
66 |
67 | @media (--dark-mode) {
68 | body {
69 | background-color: black;
70 | color: white;
71 | }
72 | }
73 |
74 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
75 |
76 | .test-custom-selectors:--heading {
77 | order: 9;
78 | }
79 |
80 | .test-case-insensitive-attributes[frame=hsides],.test-case-insensitive-attributes[frame=Hsides],.test-case-insensitive-attributes[frame=hSides],.test-case-insensitive-attributes[frame=HSides],.test-case-insensitive-attributes[frame=hsIdes],.test-case-insensitive-attributes[frame=HsIdes],.test-case-insensitive-attributes[frame=hSIdes],.test-case-insensitive-attributes[frame=HSIdes],.test-case-insensitive-attributes[frame=hsiDes],.test-case-insensitive-attributes[frame=HsiDes],.test-case-insensitive-attributes[frame=hSiDes],.test-case-insensitive-attributes[frame=HSiDes],.test-case-insensitive-attributes[frame=hsIDes],.test-case-insensitive-attributes[frame=HsIDes],.test-case-insensitive-attributes[frame=hSIDes],.test-case-insensitive-attributes[frame=HSIDes],.test-case-insensitive-attributes[frame=hsidEs],.test-case-insensitive-attributes[frame=HsidEs],.test-case-insensitive-attributes[frame=hSidEs],.test-case-insensitive-attributes[frame=HSidEs],.test-case-insensitive-attributes[frame=hsIdEs],.test-case-insensitive-attributes[frame=HsIdEs],.test-case-insensitive-attributes[frame=hSIdEs],.test-case-insensitive-attributes[frame=HSIdEs],.test-case-insensitive-attributes[frame=hsiDEs],.test-case-insensitive-attributes[frame=HsiDEs],.test-case-insensitive-attributes[frame=hSiDEs],.test-case-insensitive-attributes[frame=HSiDEs],.test-case-insensitive-attributes[frame=hsIDEs],.test-case-insensitive-attributes[frame=HsIDEs],.test-case-insensitive-attributes[frame=hSIDEs],.test-case-insensitive-attributes[frame=HSIDEs],.test-case-insensitive-attributes[frame=hsideS],.test-case-insensitive-attributes[frame=HsideS],.test-case-insensitive-attributes[frame=hSideS],.test-case-insensitive-attributes[frame=HSideS],.test-case-insensitive-attributes[frame=hsIdeS],.test-case-insensitive-attributes[frame=HsIdeS],.test-case-insensitive-attributes[frame=hSIdeS],.test-case-insensitive-attributes[frame=HSIdeS],.test-case-insensitive-attributes[frame=hsiDeS],.test-case-insensitive-attributes[frame=HsiDeS],.test-case-insensitive-attributes[frame=hSiDeS],.test-case-insensitive-attributes[frame=HSiDeS],.test-case-insensitive-attributes[frame=hsIDeS],.test-case-insensitive-attributes[frame=HsIDeS],.test-case-insensitive-attributes[frame=hSIDeS],.test-case-insensitive-attributes[frame=HSIDeS],.test-case-insensitive-attributes[frame=hsidES],.test-case-insensitive-attributes[frame=HsidES],.test-case-insensitive-attributes[frame=hSidES],.test-case-insensitive-attributes[frame=HSidES],.test-case-insensitive-attributes[frame=hsIdES],.test-case-insensitive-attributes[frame=HsIdES],.test-case-insensitive-attributes[frame=hSIdES],.test-case-insensitive-attributes[frame=HSIdES],.test-case-insensitive-attributes[frame=hsiDES],.test-case-insensitive-attributes[frame=HsiDES],.test-case-insensitive-attributes[frame=hSiDES],.test-case-insensitive-attributes[frame=HSiDES],.test-case-insensitive-attributes[frame=hsIDES],.test-case-insensitive-attributes[frame=HsIDES],.test-case-insensitive-attributes[frame=hSIDES],.test-case-insensitive-attributes[frame=HSIDES] {
81 | order: 10;
82 | }
83 |
84 | .test-rebeccapurple-color {
85 | color: rebeccapurple;
86 | order: 11;
87 | }
88 |
89 | .test-hexadecimal-alpha-notation {
90 | background-color: rgba(243,243,243,0.95294);
91 | color: rgba(0,0,0,0.2);
92 | order: 12;
93 | }
94 |
95 | .test-color-functional-notation {
96 | color: rgb(70% 13.5% 13.5% / 50%);
97 | order: 13;
98 | }
99 |
100 | .test-lab-function {
101 | background-color: rgb(178, 34, 34);
102 | color: rgba(178, 34, 34, 0.5);
103 | order: 14;
104 | }
105 |
106 | .test-system-ui-font-family {
107 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
108 | order: 15;
109 | }
110 |
111 | .test-font-variant-property {
112 | -webkit-font-feature-settings: "smcp";
113 | font-feature-settings: "smcp";
114 | font-variant-caps: small-caps;
115 | order: 16;
116 | }
117 |
118 | .test-all-property {
119 | all: initial;
120 | order: 17;
121 | }
122 |
123 | .test-matches-pseudo-class:matches(:first-child, .special) {
124 | order: 18;
125 | }
126 |
127 | .test-not-pseudo-class:not(:first-child):not(.special) {
128 | order: 19;
129 | }
130 |
131 | .test-any-link-pseudo-class:-webkit-any-link {
132 | order: 20;
133 | }
134 |
135 | .test-any-link-pseudo-class:any-link {
136 | order: 20;
137 | }
138 |
139 | [dir="rtl"] .test-dir-pseudo-class {
140 | order: 21;
141 | }
142 |
143 | .test-overflow-wrap-property {
144 | order: 22;
145 | overflow-wrap: break-word;
146 | }
147 |
148 | .test-focus-visible-pseudo-class.focus-visible {
149 | order: 23;
150 | }
151 |
152 | .test-focus-visible-pseudo-class:focus-visible {
153 | order: 23;
154 | }
155 |
156 | .test-double-position-gradients {
157 | background-image: conic-gradient(yellowgreen 40%, gold 0deg, gold 75%, #f06 0deg);
158 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
159 | }
160 |
161 | .test-blank-pseudo-class:blank {
162 | background-color: yellow;
163 | }
164 |
165 | .test-has-pseudo-class[\:has\(.inner-class\)] {
166 | background-color: yellow;
167 | }
168 |
169 | .test-has-pseudo-class:has(.inner-class) {
170 | background-color: yellow;
171 | }
172 |
--------------------------------------------------------------------------------
/test/basic.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: var(--order);
7 | }
8 |
9 | .test-image-set-function {
10 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
11 | order: 2;
12 | }
13 |
14 | .test-logical-properties-and-values {
15 | margin: logical 1px 2px 3px 4px;
16 | order: 3;
17 | padding-block: 5px;
18 | }
19 |
20 | .test-nesting-rules {
21 | order: 4;
22 |
23 | & p {
24 | order: 5;
25 | }
26 |
27 | order: 6;
28 | }
29 |
30 | @custom-media --narrow-window (max-width: 30em);
31 |
32 | @media (--narrow-window) {
33 | .test-custom-media-queries {
34 | order: 7;
35 | }
36 | }
37 |
38 | @media (480px <= width < 768px) {
39 | .test-media-query-ranges {
40 | order: 8;
41 | }
42 | }
43 |
44 | @custom-media --dark-mode (prefers-color-scheme: dark);
45 |
46 | @media (--dark-mode) {
47 | body {
48 | background-color: black;
49 | color: white;
50 | }
51 | }
52 |
53 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
54 |
55 | .test-custom-selectors:--heading {
56 | order: 9;
57 | }
58 |
59 | .test-case-insensitive-attributes[frame=hsides i] {
60 | order: 10;
61 | }
62 |
63 | .test-rebeccapurple-color {
64 | color: rebeccapurple;
65 | order: 11;
66 | }
67 |
68 | .test-hexadecimal-alpha-notation {
69 | background-color: #f3f3f3f3;
70 | color: #0003;
71 | order: 12;
72 | }
73 |
74 | .test-color-functional-notation {
75 | color: rgb(70% 13.5% 13.5% / 50%);
76 | order: 13;
77 | }
78 |
79 | .test-lab-function {
80 | background-color: lab(40% 56.6 39);
81 | color: lch(40% 68.8 34.5 / 50%);
82 | order: 14;
83 | }
84 |
85 | .test-system-ui-font-family {
86 | font-family: system-ui;
87 | order: 15;
88 | }
89 |
90 | .test-font-variant-property {
91 | font-variant-caps: small-caps;
92 | order: 16;
93 | }
94 |
95 | .test-all-property {
96 | all: initial;
97 | order: 17;
98 | }
99 |
100 | .test-matches-pseudo-class:matches(:first-child, .special) {
101 | order: 18;
102 | }
103 |
104 | .test-not-pseudo-class:not(:first-child, .special) {
105 | order: 19;
106 | }
107 |
108 | .test-any-link-pseudo-class:any-link {
109 | order: 20;
110 | }
111 |
112 | .test-dir-pseudo-class:dir(rtl) {
113 | order: 21;
114 | }
115 |
116 | .test-overflow-wrap-property {
117 | order: 22;
118 | overflow-wrap: break-word;
119 | }
120 |
121 | .test-focus-visible-pseudo-class:focus-visible {
122 | order: 23;
123 | }
124 |
125 | .test-double-position-gradients {
126 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
127 | }
128 |
129 | .test-blank-pseudo-class:blank {
130 | background-color: yellow;
131 | }
132 |
133 | .test-has-pseudo-class:has(.inner-class) {
134 | background-color: yellow;
135 | }
136 |
--------------------------------------------------------------------------------
/test/basic.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: 1;
7 | order: var(--order);
8 | }
9 |
10 | .test-image-set-function {
11 | background-image: url(img/test.png);
12 | }
13 |
14 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
15 |
16 | .test-image-set-function {
17 | background-image: url(img/test-2x.png);
18 | }
19 | }
20 |
21 | .test-image-set-function {
22 | background-image: -webkit-image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
23 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
24 | order: 2;
25 | }
26 |
27 | [dir="ltr"] .test-logical-properties-and-values {
28 | margin: 1px 4px 3px 2px;
29 | }
30 |
31 | [dir="rtl"] .test-logical-properties-and-values {
32 | margin: 1px 2px 3px 4px;
33 | }
34 |
35 | .test-logical-properties-and-values {
36 | order: 3;
37 | padding-top: 5px;
38 | padding-bottom: 5px;
39 | }
40 |
41 | .test-nesting-rules {
42 | order: 4;
43 |
44 | & p {
45 | order: 5;
46 | }
47 |
48 | order: 6;
49 | }
50 |
51 | @custom-media --narrow-window (max-width: 30em);
52 |
53 | @media (--narrow-window) {
54 | .test-custom-media-queries {
55 | order: 7;
56 | }
57 | }
58 |
59 | @media (min-width: 480px) and (max-width: 767px) {
60 | .test-media-query-ranges {
61 | order: 8;
62 | }
63 | }
64 |
65 | @custom-media --dark-mode (prefers-color-scheme: dark);
66 |
67 | @media (--dark-mode) {
68 | body {
69 | background-color: black;
70 | color: white;
71 | }
72 | }
73 |
74 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
75 |
76 | .test-custom-selectors:--heading {
77 | order: 9;
78 | }
79 |
80 | .test-case-insensitive-attributes[frame=hsides],.test-case-insensitive-attributes[frame=Hsides],.test-case-insensitive-attributes[frame=hSides],.test-case-insensitive-attributes[frame=HSides],.test-case-insensitive-attributes[frame=hsIdes],.test-case-insensitive-attributes[frame=HsIdes],.test-case-insensitive-attributes[frame=hSIdes],.test-case-insensitive-attributes[frame=HSIdes],.test-case-insensitive-attributes[frame=hsiDes],.test-case-insensitive-attributes[frame=HsiDes],.test-case-insensitive-attributes[frame=hSiDes],.test-case-insensitive-attributes[frame=HSiDes],.test-case-insensitive-attributes[frame=hsIDes],.test-case-insensitive-attributes[frame=HsIDes],.test-case-insensitive-attributes[frame=hSIDes],.test-case-insensitive-attributes[frame=HSIDes],.test-case-insensitive-attributes[frame=hsidEs],.test-case-insensitive-attributes[frame=HsidEs],.test-case-insensitive-attributes[frame=hSidEs],.test-case-insensitive-attributes[frame=HSidEs],.test-case-insensitive-attributes[frame=hsIdEs],.test-case-insensitive-attributes[frame=HsIdEs],.test-case-insensitive-attributes[frame=hSIdEs],.test-case-insensitive-attributes[frame=HSIdEs],.test-case-insensitive-attributes[frame=hsiDEs],.test-case-insensitive-attributes[frame=HsiDEs],.test-case-insensitive-attributes[frame=hSiDEs],.test-case-insensitive-attributes[frame=HSiDEs],.test-case-insensitive-attributes[frame=hsIDEs],.test-case-insensitive-attributes[frame=HsIDEs],.test-case-insensitive-attributes[frame=hSIDEs],.test-case-insensitive-attributes[frame=HSIDEs],.test-case-insensitive-attributes[frame=hsideS],.test-case-insensitive-attributes[frame=HsideS],.test-case-insensitive-attributes[frame=hSideS],.test-case-insensitive-attributes[frame=HSideS],.test-case-insensitive-attributes[frame=hsIdeS],.test-case-insensitive-attributes[frame=HsIdeS],.test-case-insensitive-attributes[frame=hSIdeS],.test-case-insensitive-attributes[frame=HSIdeS],.test-case-insensitive-attributes[frame=hsiDeS],.test-case-insensitive-attributes[frame=HsiDeS],.test-case-insensitive-attributes[frame=hSiDeS],.test-case-insensitive-attributes[frame=HSiDeS],.test-case-insensitive-attributes[frame=hsIDeS],.test-case-insensitive-attributes[frame=HsIDeS],.test-case-insensitive-attributes[frame=hSIDeS],.test-case-insensitive-attributes[frame=HSIDeS],.test-case-insensitive-attributes[frame=hsidES],.test-case-insensitive-attributes[frame=HsidES],.test-case-insensitive-attributes[frame=hSidES],.test-case-insensitive-attributes[frame=HSidES],.test-case-insensitive-attributes[frame=hsIdES],.test-case-insensitive-attributes[frame=HsIdES],.test-case-insensitive-attributes[frame=hSIdES],.test-case-insensitive-attributes[frame=HSIdES],.test-case-insensitive-attributes[frame=hsiDES],.test-case-insensitive-attributes[frame=HsiDES],.test-case-insensitive-attributes[frame=hSiDES],.test-case-insensitive-attributes[frame=HSiDES],.test-case-insensitive-attributes[frame=hsIDES],.test-case-insensitive-attributes[frame=HsIDES],.test-case-insensitive-attributes[frame=hSIDES],.test-case-insensitive-attributes[frame=HSIDES] {
81 | order: 10;
82 | }
83 |
84 | .test-rebeccapurple-color {
85 | color: #639;
86 | order: 11;
87 | }
88 |
89 | .test-hexadecimal-alpha-notation {
90 | background-color: rgba(243,243,243,0.95294);
91 | color: rgba(0,0,0,0.2);
92 | order: 12;
93 | }
94 |
95 | .test-color-functional-notation {
96 | color: rgb(70% 13.5% 13.5% / 50%);
97 | order: 13;
98 | }
99 |
100 | .test-lab-function {
101 | background-color: rgb(178, 34, 34);
102 | color: rgba(178, 34, 34, 0.5);
103 | order: 14;
104 | }
105 |
106 | .test-system-ui-font-family {
107 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
108 | order: 15;
109 | }
110 |
111 | .test-font-variant-property {
112 | font-feature-settings: "smcp";
113 | font-variant-caps: small-caps;
114 | order: 16;
115 | }
116 |
117 | .test-all-property {
118 | -webkit-animation: none 0s ease 0s 1 normal none running;
119 | animation: none 0s ease 0s 1 normal none running;
120 | -webkit-backface-visibility: visible;
121 | backface-visibility: visible;
122 | background: transparent none repeat 0 0 / auto auto padding-box border-box scroll;
123 | border: medium none currentColor;
124 | border-collapse: separate;
125 | -o-border-image: none;
126 | border-image: none;
127 | border-radius: 0;
128 | border-spacing: 0;
129 | bottom: auto;
130 | box-shadow: none;
131 | box-sizing: content-box;
132 | caption-side: top;
133 | clear: none;
134 | clip: auto;
135 | color: #000;
136 | -moz-columns: auto;
137 | columns: auto;
138 | -moz-column-count: auto;
139 | column-count: auto;
140 | -moz-column-fill: balance;
141 | column-fill: balance;
142 | -moz-column-gap: normal;
143 | column-gap: normal;
144 | -moz-column-rule: medium none currentColor;
145 | column-rule: medium none currentColor;
146 | -moz-column-span: 1;
147 | column-span: 1;
148 | -moz-column-width: auto;
149 | column-width: auto;
150 | content: normal;
151 | counter-increment: none;
152 | counter-reset: none;
153 | cursor: auto;
154 | direction: ltr;
155 | display: inline;
156 | empty-cells: show;
157 | float: none;
158 | font-family: serif;
159 | font-size: medium;
160 | font-style: normal;
161 | font-variant: normal;
162 | font-weight: normal;
163 | font-stretch: normal;
164 | line-height: normal;
165 | height: auto;
166 | -webkit-hyphens: none;
167 | -ms-hyphens: none;
168 | hyphens: none;
169 | left: auto;
170 | letter-spacing: normal;
171 | list-style: disc outside none;
172 | margin: 0;
173 | max-height: none;
174 | max-width: none;
175 | min-height: 0;
176 | min-width: 0;
177 | opacity: 1;
178 | orphans: 2;
179 | outline: medium none invert;
180 | overflow: visible;
181 | overflow-x: visible;
182 | overflow-y: visible;
183 | padding: 0;
184 | page-break-after: auto;
185 | page-break-before: auto;
186 | page-break-inside: auto;
187 | perspective: none;
188 | perspective-origin: 50% 50%;
189 | position: static;
190 | right: auto;
191 | -moz-tab-size: 8;
192 | -o-tab-size: 8;
193 | tab-size: 8;
194 | table-layout: auto;
195 | text-align: left;
196 | -moz-text-align-last: auto;
197 | text-align-last: auto;
198 | text-decoration: none;
199 | text-indent: 0;
200 | text-shadow: none;
201 | text-transform: none;
202 | top: auto;
203 | transform: none;
204 | transform-origin: 50% 50% 0;
205 | transform-style: flat;
206 | transition: none 0s ease 0s;
207 | unicode-bidi: normal;
208 | vertical-align: baseline;
209 | visibility: visible;
210 | white-space: normal;
211 | widows: 2;
212 | width: auto;
213 | word-spacing: normal;
214 | z-index: auto;
215 | all: initial;
216 | order: 17;
217 | }
218 |
219 | .test-matches-pseudo-class:matches(:first-child, .special) {
220 | order: 18;
221 | }
222 |
223 | .test-not-pseudo-class:not(:first-child):not(.special) {
224 | order: 19;
225 | }
226 |
227 | .test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited {
228 | order: 20;
229 | }
230 |
231 | .test-any-link-pseudo-class:-webkit-any-link {
232 | order: 20;
233 | }
234 |
235 | .test-any-link-pseudo-class:-moz-any-link {
236 | order: 20;
237 | }
238 |
239 | .test-any-link-pseudo-class:any-link {
240 | order: 20;
241 | }
242 |
243 | [dir="rtl"] .test-dir-pseudo-class {
244 | order: 21;
245 | }
246 |
247 | .test-overflow-wrap-property {
248 | order: 22;
249 | word-wrap: break-word;
250 | }
251 |
252 | .test-focus-visible-pseudo-class.focus-visible {
253 | order: 23;
254 | }
255 |
256 | .test-focus-visible-pseudo-class:focus-visible {
257 | order: 23;
258 | }
259 |
260 | .test-double-position-gradients {
261 | background-image: conic-gradient(yellowgreen 40%, gold 0deg, gold 75%, #f06 0deg);
262 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
263 | }
264 |
265 | .test-blank-pseudo-class:blank {
266 | background-color: yellow;
267 | }
268 |
269 | .test-has-pseudo-class[\:has\(.inner-class\)] {
270 | background-color: yellow;
271 | }
272 |
273 | .test-has-pseudo-class:has(.inner-class) {
274 | background-color: yellow;
275 | }
276 |
--------------------------------------------------------------------------------
/test/basic.ff49.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: var(--order);
7 | }
8 |
9 | .test-image-set-function {
10 | background-image: url(img/test.png);
11 | }
12 |
13 | @media (min-resolution: 192dpi) {
14 |
15 | .test-image-set-function {
16 | background-image: url(img/test-2x.png);
17 | }
18 | }
19 |
20 | .test-image-set-function {
21 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
22 | order: 2;
23 | }
24 |
25 | .test-logical-properties-and-values {
26 | margin: logical 1px 2px 3px 4px;
27 | order: 3;
28 | padding-block: 5px;
29 | }
30 |
31 | .test-nesting-rules {
32 | order: 4;
33 |
34 | & p {
35 | order: 5;
36 | }
37 |
38 | order: 6;
39 | }
40 |
41 | @custom-media --narrow-window (max-width: 30em);
42 |
43 | @media (--narrow-window) {
44 | .test-custom-media-queries {
45 | order: 7;
46 | }
47 | }
48 |
49 | @media (min-width: 480px) and (max-width: 767px) {
50 | .test-media-query-ranges {
51 | order: 8;
52 | }
53 | }
54 |
55 | @custom-media --dark-mode (prefers-color-scheme: dark);
56 |
57 | @media (--dark-mode) {
58 | body {
59 | background-color: black;
60 | color: white;
61 | }
62 | }
63 |
64 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
65 |
66 | .test-custom-selectors:--heading {
67 | order: 9;
68 | }
69 |
70 | .test-case-insensitive-attributes[frame=hsides i] {
71 | order: 10;
72 | }
73 |
74 | .test-rebeccapurple-color {
75 | color: rebeccapurple;
76 | order: 11;
77 | }
78 |
79 | .test-hexadecimal-alpha-notation {
80 | background-color: #f3f3f3f3;
81 | color: #0003;
82 | order: 12;
83 | }
84 |
85 | .test-color-functional-notation {
86 | color: rgb(70% 13.5% 13.5% / 50%);
87 | order: 13;
88 | }
89 |
90 | .test-lab-function {
91 | background-color: rgb(178, 34, 34);
92 | color: rgba(178, 34, 34, 0.5);
93 | order: 14;
94 | }
95 |
96 | .test-system-ui-font-family {
97 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
98 | order: 15;
99 | }
100 |
101 | .test-font-variant-property {
102 | font-variant-caps: small-caps;
103 | order: 16;
104 | }
105 |
106 | .test-all-property {
107 | all: initial;
108 | order: 17;
109 | }
110 |
111 | .test-matches-pseudo-class:matches(:first-child, .special) {
112 | order: 18;
113 | }
114 |
115 | .test-not-pseudo-class:not(:first-child):not(.special) {
116 | order: 19;
117 | }
118 |
119 | .test-any-link-pseudo-class:-moz-any-link {
120 | order: 20;
121 | }
122 |
123 | .test-any-link-pseudo-class:any-link {
124 | order: 20;
125 | }
126 |
127 | .test-dir-pseudo-class:dir(rtl) {
128 | order: 21;
129 | }
130 |
131 | .test-overflow-wrap-property {
132 | order: 22;
133 | overflow-wrap: break-word;
134 | }
135 |
136 | .test-focus-visible-pseudo-class:focus-visible {
137 | order: 23;
138 | }
139 |
140 | .test-double-position-gradients {
141 | background-image: conic-gradient(yellowgreen 40%, gold 0deg, gold 75%, #f06 0deg);
142 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
143 | }
144 |
145 | .test-blank-pseudo-class:blank {
146 | background-color: yellow;
147 | }
148 |
149 | .test-has-pseudo-class[\:has\(.inner-class\)] {
150 | background-color: yellow;
151 | }
152 |
153 | .test-has-pseudo-class:has(.inner-class) {
154 | background-color: yellow;
155 | }
156 |
--------------------------------------------------------------------------------
/test/basic.nesting.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: var(--order);
7 | }
8 |
9 | .test-image-set-function {
10 | background-image: -webkit-image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
11 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
12 | order: 2;
13 | }
14 |
15 | .test-logical-properties-and-values {
16 | margin: logical 1px 2px 3px 4px;
17 | order: 3;
18 | padding-block: 5px;
19 | }
20 |
21 | .test-nesting-rules {
22 | order: 4;
23 | }
24 |
25 | .test-nesting-rules p {
26 | order: 5;
27 | }
28 |
29 | .test-nesting-rules {
30 |
31 | order: 6;
32 | }
33 |
34 | @custom-media --narrow-window (max-width: 30em);
35 |
36 | @media (--narrow-window) {
37 | .test-custom-media-queries {
38 | order: 7;
39 | }
40 | }
41 |
42 | @media (480px <= width < 768px) {
43 | .test-media-query-ranges {
44 | order: 8;
45 | }
46 | }
47 |
48 | @custom-media --dark-mode (prefers-color-scheme: dark);
49 |
50 | @media (--dark-mode) {
51 | body {
52 | background-color: black;
53 | color: white;
54 | }
55 | }
56 |
57 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
58 |
59 | .test-custom-selectors:--heading {
60 | order: 9;
61 | }
62 |
63 | .test-case-insensitive-attributes[frame=hsides i] {
64 | order: 10;
65 | }
66 |
67 | .test-rebeccapurple-color {
68 | color: rebeccapurple;
69 | order: 11;
70 | }
71 |
72 | .test-hexadecimal-alpha-notation {
73 | background-color: #f3f3f3f3;
74 | color: #0003;
75 | order: 12;
76 | }
77 |
78 | .test-color-functional-notation {
79 | color: rgb(70% 13.5% 13.5% / 50%);
80 | order: 13;
81 | }
82 |
83 | .test-lab-function {
84 | background-color: lab(40% 56.6 39);
85 | color: lch(40% 68.8 34.5 / 50%);
86 | order: 14;
87 | }
88 |
89 | .test-system-ui-font-family {
90 | font-family: system-ui;
91 | order: 15;
92 | }
93 |
94 | .test-font-variant-property {
95 | font-variant-caps: small-caps;
96 | order: 16;
97 | }
98 |
99 | .test-all-property {
100 | all: initial;
101 | order: 17;
102 | }
103 |
104 | .test-matches-pseudo-class:matches(:first-child, .special) {
105 | order: 18;
106 | }
107 |
108 | .test-not-pseudo-class:not(:first-child, .special) {
109 | order: 19;
110 | }
111 |
112 | .test-any-link-pseudo-class:-webkit-any-link {
113 | order: 20;
114 | }
115 |
116 | .test-any-link-pseudo-class:-moz-any-link {
117 | order: 20;
118 | }
119 |
120 | .test-any-link-pseudo-class:any-link {
121 | order: 20;
122 | }
123 |
124 | .test-dir-pseudo-class:dir(rtl) {
125 | order: 21;
126 | }
127 |
128 | .test-overflow-wrap-property {
129 | order: 22;
130 | overflow-wrap: break-word;
131 | }
132 |
133 | .test-focus-visible-pseudo-class:focus-visible {
134 | order: 23;
135 | }
136 |
137 | .test-double-position-gradients {
138 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
139 | }
140 |
141 | .test-blank-pseudo-class:blank {
142 | background-color: yellow;
143 | }
144 |
145 | .test-has-pseudo-class:has(.inner-class) {
146 | background-color: yellow;
147 | }
148 |
--------------------------------------------------------------------------------
/test/basic.stage0-ff49.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: var(--order);
7 | }
8 |
9 | .test-image-set-function {
10 | background-image: url(img/test.png);
11 | }
12 |
13 | @media (min-resolution: 192dpi) {
14 |
15 | .test-image-set-function {
16 | background-image: url(img/test-2x.png);
17 | }
18 | }
19 |
20 | .test-image-set-function {
21 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
22 | order: 2;
23 | }
24 |
25 | .test-logical-properties-and-values {
26 | margin: logical 1px 2px 3px 4px;
27 | order: 3;
28 | padding-block: 5px;
29 | }
30 |
31 | .test-nesting-rules {
32 | order: 4;
33 | }
34 |
35 | .test-nesting-rules p {
36 | order: 5;
37 | }
38 |
39 | .test-nesting-rules {
40 |
41 | order: 6;
42 | }
43 |
44 | @media (max-width: 30em) {
45 | .test-custom-media-queries {
46 | order: 7;
47 | }
48 | }
49 |
50 | @media (min-width: 480px) and (max-width: 767px) {
51 | .test-media-query-ranges {
52 | order: 8;
53 | }
54 | }
55 |
56 | @media (color-index: 48) {
57 | body {
58 | background-color: black;
59 | color: white;
60 | }
61 | }
62 |
63 | @media (prefers-color-scheme: dark) {
64 | body {
65 | background-color: black;
66 | color: white;
67 | }
68 | }
69 |
70 | h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors {
71 | order: 9;
72 | }
73 |
74 | .test-case-insensitive-attributes[frame=hsides i] {
75 | order: 10;
76 | }
77 |
78 | .test-rebeccapurple-color {
79 | color: rebeccapurple;
80 | order: 11;
81 | }
82 |
83 | .test-hexadecimal-alpha-notation {
84 | background-color: #f3f3f3f3;
85 | color: #0003;
86 | order: 12;
87 | }
88 |
89 | .test-color-functional-notation {
90 | color: rgba(178, 34, 34, 0.5);
91 | order: 13;
92 | }
93 |
94 | .test-lab-function {
95 | background-color: rgb(178, 34, 34);
96 | color: rgba(178, 34, 34, 0.5);
97 | order: 14;
98 | }
99 |
100 | .test-system-ui-font-family {
101 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
102 | order: 15;
103 | }
104 |
105 | .test-font-variant-property {
106 | font-variant-caps: small-caps;
107 | order: 16;
108 | }
109 |
110 | .test-all-property {
111 | all: initial;
112 | order: 17;
113 | }
114 |
115 | .test-matches-pseudo-class:matches(:first-child, .special) {
116 | order: 18;
117 | }
118 |
119 | .test-not-pseudo-class:not(:first-child):not(.special) {
120 | order: 19;
121 | }
122 |
123 | .test-any-link-pseudo-class:-moz-any-link {
124 | order: 20;
125 | }
126 |
127 | .test-any-link-pseudo-class:any-link {
128 | order: 20;
129 | }
130 |
131 | .test-dir-pseudo-class:dir(rtl) {
132 | order: 21;
133 | }
134 |
135 | .test-overflow-wrap-property {
136 | order: 22;
137 | overflow-wrap: break-word;
138 | }
139 |
140 | .test-focus-visible-pseudo-class:focus-visible {
141 | order: 23;
142 | }
143 |
144 | .test-double-position-gradients {
145 | background-image: conic-gradient(yellowgreen 40%, gold 0deg, gold 75%, #f06 0deg);
146 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
147 | }
148 |
149 | .test-blank-pseudo-class[blank] {
150 | background-color: yellow;
151 | }
152 |
153 | .test-blank-pseudo-class:blank {
154 | background-color: yellow;
155 | }
156 |
157 | .test-has-pseudo-class[\:has\(.inner-class\)] {
158 | background-color: yellow;
159 | }
160 |
161 | .test-has-pseudo-class:has(.inner-class) {
162 | background-color: yellow;
163 | }
164 |
--------------------------------------------------------------------------------
/test/basic.stage0.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --order: 1;
3 | }
4 |
5 | .test-custom-properties {
6 | order: 1;
7 | order: var(--order);
8 | }
9 |
10 | .test-image-set-function {
11 | background-image: url(img/test.png);
12 | }
13 |
14 | @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) {
15 |
16 | .test-image-set-function {
17 | background-image: url(img/test-2x.png);
18 | }
19 | }
20 |
21 | .test-image-set-function {
22 | background-image: -webkit-image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
23 | background-image: image-set(url(img/test.png) 1x, url(img/test-2x.png) 2x);
24 | order: 2;
25 | }
26 |
27 | [dir="ltr"] .test-logical-properties-and-values {
28 | margin: 1px 4px 3px 2px;
29 | }
30 |
31 | [dir="rtl"] .test-logical-properties-and-values {
32 | margin: 1px 2px 3px 4px;
33 | }
34 |
35 | .test-logical-properties-and-values {
36 | order: 3;
37 | padding-top: 5px;
38 | padding-bottom: 5px;
39 | }
40 |
41 | .test-nesting-rules {
42 | order: 4;
43 | }
44 |
45 | .test-nesting-rules p {
46 | order: 5;
47 | }
48 |
49 | .test-nesting-rules {
50 |
51 | order: 6;
52 | }
53 |
54 | @media (max-width: 30em) {
55 | .test-custom-media-queries {
56 | order: 7;
57 | }
58 | }
59 |
60 | @media (min-width: 480px) and (max-width: 767px) {
61 | .test-media-query-ranges {
62 | order: 8;
63 | }
64 | }
65 |
66 | @media (color-index: 48) {
67 | body {
68 | background-color: black;
69 | color: white;
70 | }
71 | }
72 |
73 | @media (prefers-color-scheme: dark) {
74 | body {
75 | background-color: black;
76 | color: white;
77 | }
78 | }
79 |
80 | h1.test-custom-selectors,h2.test-custom-selectors,h3.test-custom-selectors,h4.test-custom-selectors,h5.test-custom-selectors,h6.test-custom-selectors {
81 | order: 9;
82 | }
83 |
84 | .test-case-insensitive-attributes[frame=hsides],.test-case-insensitive-attributes[frame=Hsides],.test-case-insensitive-attributes[frame=hSides],.test-case-insensitive-attributes[frame=HSides],.test-case-insensitive-attributes[frame=hsIdes],.test-case-insensitive-attributes[frame=HsIdes],.test-case-insensitive-attributes[frame=hSIdes],.test-case-insensitive-attributes[frame=HSIdes],.test-case-insensitive-attributes[frame=hsiDes],.test-case-insensitive-attributes[frame=HsiDes],.test-case-insensitive-attributes[frame=hSiDes],.test-case-insensitive-attributes[frame=HSiDes],.test-case-insensitive-attributes[frame=hsIDes],.test-case-insensitive-attributes[frame=HsIDes],.test-case-insensitive-attributes[frame=hSIDes],.test-case-insensitive-attributes[frame=HSIDes],.test-case-insensitive-attributes[frame=hsidEs],.test-case-insensitive-attributes[frame=HsidEs],.test-case-insensitive-attributes[frame=hSidEs],.test-case-insensitive-attributes[frame=HSidEs],.test-case-insensitive-attributes[frame=hsIdEs],.test-case-insensitive-attributes[frame=HsIdEs],.test-case-insensitive-attributes[frame=hSIdEs],.test-case-insensitive-attributes[frame=HSIdEs],.test-case-insensitive-attributes[frame=hsiDEs],.test-case-insensitive-attributes[frame=HsiDEs],.test-case-insensitive-attributes[frame=hSiDEs],.test-case-insensitive-attributes[frame=HSiDEs],.test-case-insensitive-attributes[frame=hsIDEs],.test-case-insensitive-attributes[frame=HsIDEs],.test-case-insensitive-attributes[frame=hSIDEs],.test-case-insensitive-attributes[frame=HSIDEs],.test-case-insensitive-attributes[frame=hsideS],.test-case-insensitive-attributes[frame=HsideS],.test-case-insensitive-attributes[frame=hSideS],.test-case-insensitive-attributes[frame=HSideS],.test-case-insensitive-attributes[frame=hsIdeS],.test-case-insensitive-attributes[frame=HsIdeS],.test-case-insensitive-attributes[frame=hSIdeS],.test-case-insensitive-attributes[frame=HSIdeS],.test-case-insensitive-attributes[frame=hsiDeS],.test-case-insensitive-attributes[frame=HsiDeS],.test-case-insensitive-attributes[frame=hSiDeS],.test-case-insensitive-attributes[frame=HSiDeS],.test-case-insensitive-attributes[frame=hsIDeS],.test-case-insensitive-attributes[frame=HsIDeS],.test-case-insensitive-attributes[frame=hSIDeS],.test-case-insensitive-attributes[frame=HSIDeS],.test-case-insensitive-attributes[frame=hsidES],.test-case-insensitive-attributes[frame=HsidES],.test-case-insensitive-attributes[frame=hSidES],.test-case-insensitive-attributes[frame=HSidES],.test-case-insensitive-attributes[frame=hsIdES],.test-case-insensitive-attributes[frame=HsIdES],.test-case-insensitive-attributes[frame=hSIdES],.test-case-insensitive-attributes[frame=HSIdES],.test-case-insensitive-attributes[frame=hsiDES],.test-case-insensitive-attributes[frame=HsiDES],.test-case-insensitive-attributes[frame=hSiDES],.test-case-insensitive-attributes[frame=HSiDES],.test-case-insensitive-attributes[frame=hsIDES],.test-case-insensitive-attributes[frame=HsIDES],.test-case-insensitive-attributes[frame=hSIDES],.test-case-insensitive-attributes[frame=HSIDES] {
85 | order: 10;
86 | }
87 |
88 | .test-rebeccapurple-color {
89 | color: #639;
90 | order: 11;
91 | }
92 |
93 | .test-hexadecimal-alpha-notation {
94 | background-color: rgba(243,243,243,0.95294);
95 | color: rgba(0,0,0,0.2);
96 | order: 12;
97 | }
98 |
99 | .test-color-functional-notation {
100 | color: rgba(178, 34, 34, 0.5);
101 | order: 13;
102 | }
103 |
104 | .test-lab-function {
105 | background-color: rgb(178, 34, 34);
106 | color: rgba(178, 34, 34, 0.5);
107 | order: 14;
108 | }
109 |
110 | .test-system-ui-font-family {
111 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
112 | order: 15;
113 | }
114 |
115 | .test-font-variant-property {
116 | font-feature-settings: "smcp";
117 | font-variant-caps: small-caps;
118 | order: 16;
119 | }
120 |
121 | .test-all-property {
122 | -webkit-animation: none 0s ease 0s 1 normal none running;
123 | animation: none 0s ease 0s 1 normal none running;
124 | -webkit-backface-visibility: visible;
125 | backface-visibility: visible;
126 | background: transparent none repeat 0 0 / auto auto padding-box border-box scroll;
127 | border: medium none currentColor;
128 | border-collapse: separate;
129 | -o-border-image: none;
130 | border-image: none;
131 | border-radius: 0;
132 | border-spacing: 0;
133 | bottom: auto;
134 | box-shadow: none;
135 | box-sizing: content-box;
136 | caption-side: top;
137 | clear: none;
138 | clip: auto;
139 | color: #000;
140 | -moz-columns: auto;
141 | columns: auto;
142 | -moz-column-count: auto;
143 | column-count: auto;
144 | -moz-column-fill: balance;
145 | column-fill: balance;
146 | -moz-column-gap: normal;
147 | column-gap: normal;
148 | -moz-column-rule: medium none currentColor;
149 | column-rule: medium none currentColor;
150 | -moz-column-span: 1;
151 | column-span: 1;
152 | -moz-column-width: auto;
153 | column-width: auto;
154 | content: normal;
155 | counter-increment: none;
156 | counter-reset: none;
157 | cursor: auto;
158 | direction: ltr;
159 | display: inline;
160 | empty-cells: show;
161 | float: none;
162 | font-family: serif;
163 | font-size: medium;
164 | font-style: normal;
165 | font-variant: normal;
166 | font-weight: normal;
167 | font-stretch: normal;
168 | line-height: normal;
169 | height: auto;
170 | -webkit-hyphens: none;
171 | -ms-hyphens: none;
172 | hyphens: none;
173 | left: auto;
174 | letter-spacing: normal;
175 | list-style: disc outside none;
176 | margin: 0;
177 | max-height: none;
178 | max-width: none;
179 | min-height: 0;
180 | min-width: 0;
181 | opacity: 1;
182 | orphans: 2;
183 | outline: medium none invert;
184 | overflow: visible;
185 | overflow-x: visible;
186 | overflow-y: visible;
187 | padding: 0;
188 | page-break-after: auto;
189 | page-break-before: auto;
190 | page-break-inside: auto;
191 | perspective: none;
192 | perspective-origin: 50% 50%;
193 | position: static;
194 | right: auto;
195 | -moz-tab-size: 8;
196 | -o-tab-size: 8;
197 | tab-size: 8;
198 | table-layout: auto;
199 | text-align: left;
200 | -moz-text-align-last: auto;
201 | text-align-last: auto;
202 | text-decoration: none;
203 | text-indent: 0;
204 | text-shadow: none;
205 | text-transform: none;
206 | top: auto;
207 | transform: none;
208 | transform-origin: 50% 50% 0;
209 | transform-style: flat;
210 | transition: none 0s ease 0s;
211 | unicode-bidi: normal;
212 | vertical-align: baseline;
213 | visibility: visible;
214 | white-space: normal;
215 | widows: 2;
216 | width: auto;
217 | word-spacing: normal;
218 | z-index: auto;
219 | all: initial;
220 | order: 17;
221 | }
222 |
223 | .test-matches-pseudo-class:matches(:first-child, .special) {
224 | order: 18;
225 | }
226 |
227 | .test-not-pseudo-class:not(:first-child):not(.special) {
228 | order: 19;
229 | }
230 |
231 | .test-any-link-pseudo-class:link,.test-any-link-pseudo-class:visited {
232 | order: 20;
233 | }
234 |
235 | .test-any-link-pseudo-class:-webkit-any-link {
236 | order: 20;
237 | }
238 |
239 | .test-any-link-pseudo-class:-moz-any-link {
240 | order: 20;
241 | }
242 |
243 | .test-any-link-pseudo-class:any-link {
244 | order: 20;
245 | }
246 |
247 | [dir="rtl"] .test-dir-pseudo-class {
248 | order: 21;
249 | }
250 |
251 | .test-overflow-wrap-property {
252 | order: 22;
253 | word-wrap: break-word;
254 | }
255 |
256 | .test-focus-visible-pseudo-class.focus-visible {
257 | order: 23;
258 | }
259 |
260 | .test-focus-visible-pseudo-class:focus-visible {
261 | order: 23;
262 | }
263 |
264 | .test-double-position-gradients {
265 | background-image: conic-gradient(yellowgreen 40%, gold 0deg, gold 75%, #f06 0deg);
266 | background-image: conic-gradient(yellowgreen 40%, gold 0deg 75%, #f06 0deg);
267 | }
268 |
269 | .test-blank-pseudo-class[blank] {
270 | background-color: yellow;
271 | }
272 |
273 | .test-blank-pseudo-class:blank {
274 | background-color: yellow;
275 | }
276 |
277 | .test-has-pseudo-class[\:has\(.inner-class\)] {
278 | background-color: yellow;
279 | }
280 |
281 | .test-has-pseudo-class:has(.inner-class) {
282 | background-color: yellow;
283 | }
284 |
--------------------------------------------------------------------------------
/test/custom-properties.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --black: black;
3 | }
4 |
5 | test-css-variables {
6 | color: var(--black);
7 | }
8 |
--------------------------------------------------------------------------------
/test/custom-properties.disabled.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --black: black;
3 | }
4 |
5 | test-css-variables {
6 | color: var(--black);
7 | }
8 |
--------------------------------------------------------------------------------
/test/custom-properties.enabled.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --black: black;
3 | }
4 |
5 | test-css-variables {
6 | color: black;
7 | color: var(--black);
8 | }
9 |
--------------------------------------------------------------------------------
/test/custom-properties.expect.css:
--------------------------------------------------------------------------------
1 | :root {
2 | --black: black;
3 | }
4 |
5 | test-css-variables {
6 | color: black;
7 | color: var(--black);
8 | }
9 |
--------------------------------------------------------------------------------
/test/generated-custom-exports.css:
--------------------------------------------------------------------------------
1 | @custom-media --narrow-window (max-width: 30em);
2 | @custom-media --dark-mode (prefers-color-scheme: dark);
3 |
4 | @custom-selector :--heading h1, h2, h3, h4, h5, h6;
5 |
6 | :root {
7 | --order: 1;
8 | }
9 |
--------------------------------------------------------------------------------
/test/generated-custom-exports.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | customMedia: {
3 | '--narrow-window': '(max-width: 30em)',
4 | '--dark-mode': '(prefers-color-scheme: dark)'
5 | },
6 | customProperties: {
7 | '--order': '1'
8 | },
9 | customSelectors: {
10 | ':--heading': 'h1, h2, h3, h4, h5, h6'
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/test/generated-custom-exports.json:
--------------------------------------------------------------------------------
1 | {
2 | "custom-media": {
3 | "--narrow-window": "(max-width: 30em)",
4 | "--dark-mode": "(prefers-color-scheme: dark)"
5 | },
6 | "custom-properties": {
7 | "--order": "1"
8 | },
9 | "custom-selectors": {
10 | ":--heading": "h1, h2, h3, h4, h5, h6"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/test/generated-custom-exports.mjs:
--------------------------------------------------------------------------------
1 | export const customMedia = {
2 | '--narrow-window': '(max-width: 30em)',
3 | '--dark-mode': '(prefers-color-scheme: dark)'
4 | };
5 |
6 | export const customProperties = {
7 | '--order': '1'
8 | };
9 |
10 | export const customSelectors = {
11 | ':--heading': 'h1, h2, h3, h4, h5, h6'
12 | };
13 |
--------------------------------------------------------------------------------
/test/import.css:
--------------------------------------------------------------------------------
1 | .test-custom-properties {
2 | order: var(--order);
3 | }
4 |
5 | @media (--narrow-window) {
6 | .test-custom-media-queries {
7 | order: 2;
8 | }
9 | }
10 |
11 | .test-custom-selectors {
12 | &:--heading {
13 | order: 3;
14 | }
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/test/import.expect.css:
--------------------------------------------------------------------------------
1 | .test-custom-properties {
2 | order: 1;
3 | order: var(--order);
4 | }
5 |
6 | @media (max-width: 40rem) {
7 | .test-custom-media-queries {
8 | order: 2;
9 | }
10 | }
11 |
12 | .test-custom-selectors:is(h1),.test-custom-selectors:is(h2),.test-custom-selectors:is(h3),.test-custom-selectors:is(h4),.test-custom-selectors:is(h5),.test-custom-selectors:is(h6) {
13 | order: 3;
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/test/insert.after.expect.css:
--------------------------------------------------------------------------------
1 | $font: system-ui;
2 |
3 | .test-variable {
4 | font-family: $font;
5 | }
6 |
--------------------------------------------------------------------------------
/test/insert.before.expect.css:
--------------------------------------------------------------------------------
1 | .test-variable {
2 | font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif;
3 | }
4 |
--------------------------------------------------------------------------------
/test/insert.css:
--------------------------------------------------------------------------------
1 | $font: system-ui;
2 |
3 | .test-variable {
4 | font-family: $font;
5 | }
6 |
--------------------------------------------------------------------------------