-
Notifications
You must be signed in to change notification settings - Fork 72
Description
Describe the bug
When at-rules are nested inside another at-rule, they are not sorted.
This is unexpected and can cause significant production issues (especially when production apps are configured differently to development environments).
Example:
const styles = cssMap({
root: {
'@supports not (-moz-appearance: none)': {
'@media (prefers-reduced-motion: no-preference) and (min-width: 64rem)': {
color: 'blue',
},
'@media (prefers-reduced-motion: no-preference)': {
color: 'green',
},
},
},
});
In this example, we would expect color: 'blue'
to "win" on large viewports (width than 64rem
). However this doesn't consistently happen in apps.
This appears to be because the sortAtomicStyleSheet function only looks at the nodes at the first level.
There is a comment here also confirming this: https://github.com/atlassian-labs/compiled/blob/master/packages/css/src/plugins/sort-atomic-style-sheet.ts#L39
* Only top level CSS rules will be sorted.
Nesting at-rules like this is valid CSS: https://css-tricks.com/can-you-nest-media-and-support-queries/
To Reproduce
You can test the current behaviour by adding the following tests to packages/css/src/plugins/tests/sort-at-rules.test.ts:
it.only('should support nested queries with multiple at-rules', () => {
const actual = transform(`
@supports not (height: 1lh) {
color: red;
@media (prefers-reduced-motion: no-preference) and (width > 1500px) {
color: blue;
}
@media (prefers-reduced-motion: no-preference) {
color: green;
}
}
`);
expect(actual).toMatchInlineSnapshot(`
"
@supports not (height: 1lh) {
color: red;
@media (prefers-reduced-motion: no-preference) and (width > 1500px) {
color: blue;
}
@media (prefers-reduced-motion: no-preference) {
color: green;
}
}
"
`);
});
it.only('should support nested queries with multiple at-rules', () => {
const actual = transform(`
color: red;
@media (prefers-reduced-motion: no-preference) and (width > 1500px) {
@supports not (height: 1lh) {
color: blue;
}
}
@media (prefers-reduced-motion: no-preference) {
@supports not (height: 1lh) {
color: green;
}
}
`);
expect(actual).toMatchInlineSnapshot(`
"
color: red;
@media (prefers-reduced-motion: no-preference) {
@supports not (height: 1lh) {
color: green;
}
}
@media (prefers-reduced-motion: no-preference) and (width > 1500px) {
@supports not (height: 1lh) {
color: blue;
}
}
"
`);
});
Expected behavior
Nested media queries should be sorted.
At a minimum, some improved guidance and lint rules to make people aware would be really helpful.
Workaround
The current workaround we are using is just making sure all at-rules that require sorting (e.g. @media
) are at the top level. For my specific example, flipping the order of the at-rules to place the @media
at the top level and have @supports
nested at the second level would make sure the media queries are sorted.
Additional context
Related issue about not merging duplicate styles in nested media queries: #1847